Search code examples
javascriptimageperformancesliderbackground-image

Is there a more efficient way to load and display multiple background-images in a slider


I currently have an imageslider function in JavaScript which switches out one image for another when the user clicks on media arrows .. it works fine, BUT there is a lag the first time it loads each image. My question is this... is there a more efficient way to load multiple images at the same time then hide/make visible instead of loading each image one at a time (using div background-image)? Here is the JavaScript function I am currently using...

let imageNames = [];

function slideImage(offset = 0) {
  var pc = document.querySelector(".slider");
  var imageLocation = "/image/profile/";

  let maxCount = imageNames.length - 1;

  if (typeof index === "undefined") {
    index = 0;
  } else {
    index += offset;

    if (index > maxCount) {
      index = 0;
    } else if (index < 0) {
      index = maxCount;
    }
  }

  pc.style.backgroundImage = "URL('" + imageLocation + imageNames[index] + ".webp')";
}

Solution

  • Here is one example of asynchronously loading all your images, using fetch().

    If you run the code snippet, you'll see there is a short delay before you can start displaying images. But then the rest of the images are loaded in the background, so on subsequent clicks there will be more (if not all) images ready to display.

    See lines marked with EDIT for details on specific changes and (mostly) additions to your code.

    // EDIT Added as it was being used in the original code
    let index
    
    
    let imageNames = [
      // EDIT image paths are now added here by preLoadImages( )
    ]
    
    // EDIT added list of image urls to be preloaded by preLoadImages( )
    let remoteImageNames = [
      "https://picsum.photos/1200/1300",
      "https://picsum.photos/1200/1310",
      "https://picsum.photos/1200/1320",
      "https://picsum.photos/1200/1330",
      "https://picsum.photos/1210/1300",
      "https://picsum.photos/1220/1310",
      "https://picsum.photos/1230/1320",
      "https://picsum.photos/1240/1330",
    ];
    
    
    // EDIT added call to new function
    preLoadImages( )
    
    
    // EDIT added function
    function preLoadImages( ) {
      for( let image of remoteImageNames ) {
        getImageDataURL( image, imgUrl => {
          imageNames.push( imgUrl )
    
          document.querySelector(".slider").innerText = "CLICK FOR NEXT IMAGE"
        } )
      }
    }
    
    
    function slideImage(offset = 0) {
      var pc = document.querySelector(".slider");
      // EDIT for demo
      // var imageLocation = "/image/profile/";
      var imageLocation = "";
    
      let maxCount = imageNames.length - 1;
    
      if (typeof index === "undefined") {
        index = 0;
      } else {
        index += offset;
    
        if (index > maxCount) {
          index = 0;
        } else if (index < 0) {
          index = maxCount;
        }
      }
    
      // EDIT for demo
      // pc.style.backgroundImage = "URL('" + imageLocation + imageNames[index] + ".webp')";
      pc.style.backgroundImage = "URL('" + imageLocation + imageNames[index] + "')";
    }
    
    
    // EDIT added function
    //
    // fetch()'s image specified in the url
    function getImageDataURL( url, callback=null ) {
      fetch( url )
      .then( result => result.blob() )
      .then( blob => {
        let fileReader = new FileReader( );
    
        fileReader.onload = event => {  // loadend event happens successfull or not. load event happens only for success
          if( callback ) callback( fileReader.result );
        };
        fileReader.readAsDataURL( blob );  // Trigger file read
      } )
    }
    .slider {
      width:  400px;
      height: 400px;
      border: 1px solid gray;
      box-shadow: 2px 2px 4px black;
      border-radius: 10px;
      margin: 20px;
      background-size: contain;
      background-repeat: no-repeat;
    }
            <div class="slider" onclick="slideImage(1)">
              PLEASE WAIT...
            </div>