Understand Javascript image preloading

  • 2021-01-03 20:48:46
  • OfStack

Preloading images is a great way to improve the user experience. Images are pre-loaded into the browser, and visitors can easily surf your site and enjoy extremely fast loading times. This is a 10 point advantage for photo galleries and sites with a high percentage of images. It ensures that images are posted quickly and seamlessly, and also helps users have a better user experience when viewing your site's content. This article will share three different pre-loading techniques to enhance the performance and usability of your site.

Method 1: Implement preloading with CSS and JavaScript

There are many ways to implement preloaded images, including using CSS, JavaScript, and various combinations of the two. These techniques can be used to design solutions based on different design scenarios, with 10 points of efficiency.

With CSS alone, images can be easily and efficiently preloaded with the following code:


#preload-01 { background: url(http://domain.tld/image-01.png) no-repeat -9999px -9999px; }
#preload-02 { background: url(http://domain.tld/image-02.png) no-repeat -9999px -9999px; }
#preload-03 { background: url(http://domain.tld/image-03.png) no-repeat -9999px -9999px; } 

By applying the three ID selectors to the (X)HTML element, we can preload an image onto an off-screen background using the background attribute of CSS. As long as the path of these images remains the same, the browser will use the preloaded (cached) images during the rendering process when they are called elsewhere on the Web page. Simple, efficient and does not require any JavaScript.

Although this method is efficient, there is still room for improvement. The image loaded by this method will be loaded together with other contents of the page 1, which increases the overall loading time of the page. To solve this problem, we added a bit of JavaScript code to delay the preload until the page is loaded. The code is as follows:


function preloader() {
  if (document.getElementById) {
    document.getElementById("preload-01").style.background = "url(http://domain.tld/image-01.png) no-repeat -9999px -9999px";
    document.getElementById("preload-02").style.background = "url(http://domain.tld/image-02.png) no-repeat -9999px -9999px";
    document.getElementById("preload-03").style.background = "url(http://domain.tld/image-03.png) no-repeat -9999px -9999px";
  }
}
function addLoadEvent(func) {
  var oldonload = window.onload;
  if (typeof window.onload != 'function') {
    window.onload = func;
  } else {
    window.onload = function() {
      if (oldonload) {
        oldonload();
      }
      func();
    }
  }
}
addLoadEvent(preloader);

In part 1 of the script, we get the element that uses the class selector and set the background attribute to it to preload the different images.

In part 2 of the script, we used the addLoadEvent() function to delay the load time of the preloader() function until the page was loaded.

What happens if JavaScript doesn't work in the user's browser? Very simple, the image will not be pre-loaded, when the page calls the image, the normal display.

Method 2: Use JavaScript only for preloading

The above approach is sometimes very efficient, but we are finding that it takes too much time to implement in practice. Instead, I prefer to use pure JavaScript for image preloading. Here are two such pre-loading methods that work beautifully on all modern browsers.

JavaScript snippet 1

Simply edit and load the path and name of the image needed, which is easy to achieve:


<div class="hidden">
  <script type="text/javascript">
      var images = new Array()
      function preload() {
        for (i = 0; i < preload.arguments.length; i++) {
          images[i] = new Image()
          images[i].src = preload.arguments[i]
        }
      }
      preload(
        "http://domain.tld/gallery/image-001.jpg",
        "http://domain.tld/gallery/image-002.jpg",
        "http://domain.tld/gallery/image-003.jpg"
      )
  </script>
</div>

This method is especially suitable for preloading large numbers of images. My gallery site uses this technique and has more than 50 pre-loaded images. Apply the script to the login page and most of the gallery images will be preloaded as soon as the user enters the login account.

JavaScript code snippet 2

This method is similar to the one above, but can also preload any number of images. Add the following script to any Web page and edit according to the program instructions.


<div class="hidden">
  <script type="text/javascript">
      if (document.images) {
        img1 = new Image();
        img2 = new Image();
        img3 = new Image();
        img1.src = "http://domain.tld/path/to/image-001.gif";
        img2.src = "http://domain.tld/path/to/image-002.gif";
        img3.src = "http://domain.tld/path/to/image-003.gif";
      }
  </script>
</div>
 

As you can see, each image load requires the creation of a variable, such as "img1 = new Image();" , and image source address declaration, such as "img3.src = ".. / path/to/image - 003. gif ";" . With this mode in mind, you can load as many images as you want.

We improved the method again. Marshal the script into one function and use addLoadEvent () to delay the preload time until the page has been loaded.


function preloader() {
  if (document.images) {
    var img1 = new Image();
    var img2 = new Image();
    var img3 = new Image();
    img1.src = "http://domain.tld/path/to/image-001.gif";
    img2.src = "http://domain.tld/path/to/image-002.gif";
    img3.src = "http://domain.tld/path/to/image-003.gif";
  }
}
function addLoadEvent(func) {
  var oldonload = window.onload;
  if (typeof window.onload != 'function') {
    window.onload = func;
  } else {
    window.onload = function() {
      if (oldonload) {
        oldonload();
      }
      func();
    }
  }
}
addLoadEvent(preloader);

Method 3: Use Ajax for preloading

As if the above method isn't cool enough, let's take a look at one that uses Ajax for image preloading. This method uses DOM to preload not only images, but also CSS, JavaScript and other related things. The advantage of using Ajax over using JavaScript is that the loading of JavaScript and CSS does not affect the current page. This method is simple and efficient.


window.onload = function() {
  setTimeout(function() {
    // XHR to request a JS and a CSS
    var xhr = new XMLHttpRequest();
    xhr.open('GET', 'http://domain.tld/preload.js');
    xhr.send('');
    xhr = new XMLHttpRequest();
    xhr.open('GET', 'http://domain.tld/preload.css');
    xhr.send('');
    // preload image
    new Image().src = "http://domain.tld/preload.png";
  }, 1000);
};

The above code preloads "preload. js", "preload. css", and "preload. png". The 1000-millisecond timeout is meant to prevent the script from hanging and causing functional problems on the normal page.

Let's look at how to implement this loading process with JavaScript:


window.onload = function() {
 
  setTimeout(function() {
 
    // reference to <head>
    var head = document.getElementsByTagName('head')[0];
 
    // a new CSS
    var css = document.createElement('link');
    css.type = "text/css";
    css.rel = "stylesheet";
    css.href = "http://domain.tld/preload.css";
 
    // a new JS
    var js = document.createElement("script");
    js.type = "text/javascript";
    js.src = "http://domain.tld/preload.js";
 
    // preload JS and CSS
    head.appendChild(css);
    head.appendChild(js);
 
    // preload image
    new Image().src = "http://domain.tld/preload.png";
 
  }, 1000);
 
};

Here, we create three elements with DOM to preload three files. As mentioned above, with Ajax, the load file is not applied to the load page. From this point of view, Ajax method is superior to JavaScript.

Added: Callbacks are loaded

Let's write the following code:


function loadImage(url, callback) {
 var img = new Image();
 img.src = url;

 img.onload = function(){ // It is called asynchronously when the picture is downloaded callback Function. 
  callback.call(img);  //  will callback function this Switch pointer to img . 
 };
}

In firefox test 1, found good, and expected effect 1, after the image download, the width of the image will pop up. The result is the same no matter how many clicks or refreshes.

Don't get too excited about this step though -- you still have 1 browser compatibility to consider, so try 1 in ie. Yes, it pops up the width of the image as well. However, when you click on load again, the situation is different and nothing happens. Same thing with refresh 1.

After testing multiple browser versions, ie6 and opera did the same, while firefox and safari performed normally. In fact, the reason is quite simple, because the browser cache. After the image has been loaded once, if there is another request for the image, since the browser has already cached the image, it will not make a new request, but will be loaded directly from the cache. For firefox and safari, their views make these two loading methods transparent to the user and also cause onload events for images, while ie and opera ignore this similarity and do not raise onload events for images, so the above code cannot be implemented in them.

What to do? In the best case, Image can have a status value indicating whether it has loaded successfully. When loaded from the cache, the status value indicates that the download has been made because there is no waiting, while when the request is loaded from http, the status value is shown as incomplete because there is waiting for the download. In that case, we're done.

After some analysis, I finally found a property of Image that is compatible with all browsers -- complete. So, just make a judgment on this value before the onload event. Finally, the code looks like this:


function loadImage(url, callback) {
  var img = new Image(); // create 1 a Image Object to realize the pre-download of the picture 
  img.src = url;
  
  if (img.complete) { //  If the image already exists in the browser cache, call the callback function directly 
    callback.call(img);
    return; //  Just return it, no more processing onload The event 
  }

  img.onload = function () { // It is called asynchronously when the picture is downloaded callback Function. 
    callback.call(img);// Will call back the function this Replace with Image object 
  };
};

Although the code is simple, it is very useful.

Attachment: Talk about javascript image preloading again

lightbox uses pre-loading to center the image and has to wait until it is fully loaded, which is not a good experience (like the full screen effect of filick album). javascript cannot get img header data. Is this true? Here is a clever way to get javascript to get it.

Here's an example of how most people use preloading to get the size of an image:


var imgLoad = function (url, callback) {
  var img = new Image();

  img.src = url;
  if (img.complete) {
    callback(img.width, img.height);
  } else {
    img.onload = function () {
      callback(img.width, img.height);
      img.onload = null;
    };
  };

};
 You can see 

We have to wait for the image to load before we can get the size. The speed is not good, we need to improve it.

web applications differ from desktop applications in that responsiveness is the best user experience. If you want to have both speed and elegance, you must get the image size in advance. How can you get the image size before the image is loaded?

More than 10 years of experience on the Internet tells me: when the browser loads the image, you will see that the image will take up 1 block of land before it is slowly loaded, and there is no need to preset width and height attributes, because the browser can get the header data of the image. Based on this, javascript only needs to detect the size state of the image regularly to know the size ready state of the image.

Of course, there are some compatibility pitfalls in practice, for example, width and height detect the inconsistency between each browser, and the image created by webkit new Image() will be affected by the image created by url url in the loading process. After repeated testing, the best processing method is as follows:


function preloader() {
  if (document.getElementById) {
    document.getElementById("preload-01").style.background = "url(http://domain.tld/image-01.png) no-repeat -9999px -9999px";
    document.getElementById("preload-02").style.background = "url(http://domain.tld/image-02.png) no-repeat -9999px -9999px";
    document.getElementById("preload-03").style.background = "url(http://domain.tld/image-03.png) no-repeat -9999px -9999px";
  }
}
function addLoadEvent(func) {
  var oldonload = window.onload;
  if (typeof window.onload != 'function') {
    window.onload = func;
  } else {
    window.onload = function() {
      if (oldonload) {
        oldonload();
      }
      func();
    }
  }
}
addLoadEvent(preloader);
0

Call examples:


function preloader() {
  if (document.getElementById) {
    document.getElementById("preload-01").style.background = "url(http://domain.tld/image-01.png) no-repeat -9999px -9999px";
    document.getElementById("preload-02").style.background = "url(http://domain.tld/image-02.png) no-repeat -9999px -9999px";
    document.getElementById("preload-03").style.background = "url(http://domain.tld/image-03.png) no-repeat -9999px -9999px";
  }
}
function addLoadEvent(func) {
  var oldonload = window.onload;
  if (typeof window.onload != 'function') {
    window.onload = func;
  } else {
    window.onload = function() {
      if (oldonload) {
        oldonload();
      }
      func();
    }
  }
}
addLoadEvent(preloader);
1

Isn't that easy? This approach is often a few to ten times faster than onload, which can kill off ordinary web (800×600 or less) images.


Related articles: