I recently took on a project. The result is a bunch of trouble with light installation dependencies. One after another. Have a headache?

See that there are some pre-loaded study notes before. So again check look for, think to write write the preload and lazy load notes to write a complete find cartography is very troublesome! I wonder if you have any recommendations.

I have written this article for a long time, what is wrong with the place welcome comment or private chat pointed out

You can also follow my blog, which I share more articles. Here here

Preloading and lazy loading of images

The words preload and lazy load are always seen. Preloading and lazy loading are not just for loading image resources. Other resources, text, video. Will do.

One of the most common or desirable scenarios we use is loading image resources.

Here, we are only talking about loading image resources.

Image preloading

What is image preloading?

The required image resources will be loaded in advance. After loading, they will be cached locally and displayed immediately when needed, so as to achieve a good experience without waiting for direct preview in the process of preview.

In short: load before display

What scenarios might require preloading

  • comic

We know that cartoons are composed of successive pictures. When we read comics, we also read them one by one.

But if we load images when we’ve finished looking at one and moved on to the next, there will be a blank load time. Also, comic images tend to be large, and if the network is not good, the loading time will be longer. The experience goes down.

As the picture shows, if we finish watching 2 and want to watch 3, it will greatly reduce the experience if 3 is not finished loading.

If we can load 3 in advance while we’re previewing 2, we’ll show it inside when we’re looking at 3. Then the experience will be much better.

  • Photo gallery

Hopefully the user will be able to preview the image smoothly, rather than seeing the image on the next page, which hasn’t loaded yet.

Similar to comics, but the load of picture resources will be more.

  • Or other scenarios where loading would be time-consuming but you don’t want the user to see blank loads

If you want to display several pictures at a time, if you let the user load while looking, then the process of successively displaying pictures, and the phenomenon of blank will let the user see.

Especially when the network is not good, users see blank do not know whether there is no picture at all, or can not load out.

If we are using preloading, a progress bar is displayed telling the user how much is loaded, and when it is 100% loaded, it will be displayed all together.

At least the user will not see blank space, will know that it is loading, and will be able to estimate the loading speed based on the progress bar. Then the experience will go up.

Disadvantages of preloading

  • Preloading takes a lot of background resources because it is possible to load many images at once

  • Preloading takes a long time and is usually performed when users perform other operations. (Comics, for example, are preloaded when the user likes an image). Or display other information during the waiting period. (E.g. display progress bar.)

Image preloading method

Here are two common and practical methods. Each approach has advantages and disadvantages. It also has its own scenarios for use. We should choose a proper method according to the reality

1. Through CSS

steps
  • Create a label for preloading
  • Use a background image for the tag. The path of the background image is the image resource that needs to be preloaded. And move the image out of sight, or shrink it out of sight. You cannot use display=none, otherwise preloading will fail
  • When a preloaded image is used, the cached image resource is used without sending a request to the server.

demo

<! - HTML file - >
<! DOCTYPEhtml>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>CSS preload</title>
    
    <! Preload style file -->
    <link rel="stylesheet" href="./preLoad.css">
    
</head>
<body>
    <! -- Display picture when clicked -->
    <button onclick="show()">According to</button>
    
    <ul>
        <! -- Preloading tag -->
        <li id="preImg1"/>
        <li  id="preImg2"/>
        <li sid="preImg3"/>
    </ul>
</body>
<script>Var show = function () {// click the ul tag to display the image document.querySelector("ul").innerhtml =<li><img src="Https://img1.baidu.com/it/u=3263944338, 3726722345 & FM = 26 & FMT = auto&gp = 0. JPG"></li>
        <li><img src="FM = https://img2.baidu.com/it/u=2480106139, 2144834787 & 253 & FMT = auto&app = 120 & f = JPEG? W = 500 & h = 552"></li>
        <li><img src="Https://img1.baidu.com/it/u=1904128529, 1389594536 & FM = 26 & FMT = auto&gp = 0. JPG"></li>`}</script>
</html>
Copy the code
/* Preload the style file */
img {
    width: 200px;
}
/* Preload the file */
#preImg1 {
    background-image: url('https://img1.baidu.com/it/u=3263944338, 3726722345 & FM = 26 & FMT = auto&gp = 0. JPG');
    width: 0;
    height: 0;  /* Hide the label */ used for preloading
}

#preImg2 {
    background-image: url('FM = https://img2.baidu.com/it/u=2480106139, 2144834787 & 253 & FMT = auto&app = 120 & f = JPEG? W = 500 & h = 552');
    width: 0;
    height: 0;
}

#preImg3 {
    background-image: url('https://img1.baidu.com/it/u=1904128529, 1389594536 & FM = 26 & FMT = auto&gp = 0. JPG');
    width: 0;
    height: 0;
}
Copy the code
Analysis:

When the viewer opens the document for the first time, it encounters a background image resource that needs to be loaded during CSS loading, so it sends a request to the server, which returns the image resource and the viewer caches it locally.

In the developer of the browser according to the NewWork item (F12) we can see the request code is 200. Is the new response returned by the server.

At this point we first clear the browser request resource record

Then click the Show button to place the image label with SRC in the document. Display images

The newWork bar does not send a new request to the server because the server has a cache. Even the stateful code is 304 (for local resources)

2. Through JavaScript

steps
  • Store the URL of the image resource that needs to be preloaded in an array
  • Loop through the URL array to perform the following steps until the end
  • Create an image objectnew Image()
  • Specifies the value of the SRC attribute of the image object as the URL for the preloaded image
demo
<! -- HTML file -->
<! DOCTYPEhtml>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <title>JS preload</title>
    <! -- Simple style, don't worry about -->
    <style>
        ul {
            float: left;
            margin: 0;
            padding: 0;
        }

        li {
            list-style-type: none;
            float: left;
        }

        img {
            width: 100px;
            height: 100px;
        }

        #mask {
            position: absolute;
            width: 300px;
            height: 100px;
            background-color: rgb(177.177.177);
            line-height: 100px;
            text-align: center;
            color: rgb(255.255.255);
            font-size: 32px;
            font-weight: 600;
        }
    </style>
</head>

<body>
     <! -- Set mask layer to display loading progress -->
    <div id="mask">00%</div>
    <ul>
        <! -- Write the tag, it will be parsed to this point, it will load immediately -->
        <li><img src="Https://img1.baidu.com/it/u=3263944338, 3726722345 & FM = 26 & FMT = auto&gp = 0. JPG"></li>
        <li><img src="FM = https://img2.baidu.com/it/u=2480106139, 2144834787 & 253 & FMT = auto&app = 120 & f = JPEG? W = 500 & h = 552">
        </li>
        <li><img src="Https://img1.baidu.com/it/u=1904128529, 1389594536 & FM = 26 & FMT = auto&gp = 0. JPG"></li>
    </ul>
</body>
     <! Preload script file -->
<script src="./preLoad.js"></script>
</html>
Copy the code
// Preload the script file
// Preloaded image URL
const urlList = [
    'https://img1.baidu.com/it/u=3263944338, 3726722345 & FM = 26 & FMT = auto&gp = 0. JPG'.'FM = https://img2.baidu.com/it/u=2480106139, 2144834787 & 253 & FMT = auto&app = 120 & f = JPEG? W = 500 & h = 552'.'https://img1.baidu.com/it/u=1904128529, 1389594536 & FM = 26 & FMT = auto&gp = 0. JPG']

// The preload function hides the mask layer after loading
function preLoad() {
    let process = document.querySelector('#mask'),  // Mask layer, used to modify progress and hide
        len = urlList.length,// Add the URL array length to provide performance
        count = 0.// Calculate the number of loads and modification progress
        ul = document.querySelector("ul"), // Place the image here
        imgList="";  // img tag string temporary storage point to avoid DOM refresh times.
 
     // In order to simulate multi-image resources and slow down the loading process, a timer is used instead of iterating through the URL array.
    let id = setInterval(() = > {
        let img = new Image()
        img.src = urlList[count]
        imgList += `<li><img src="${urlList[count]}"></li>`
        img.onload = img.onerror = function () {
            count++;
            process.innerText = (count / len * 100).toFixed(2) + The '%'; // Set the percentage of progress
            if (count === len) {
                clearInterval(id)
                ul.innerHTML += imgList;
                process.style.display = 'none'}}},500)}// Call the preload function
preLoad()
Copy the code
Analysis of the

When we need to display a large number of images, we first display other or have some loading prompts. Execute the preload function at the same time. Here we use a mask layer and progress display

The preload function loads the image resource and caches it locally, not displaying it. But there is a cache. During the loading process, progress increases as the number of loads completed increases.

When it’s all loaded, add the image dynamically to the page, hiding the mask layer. Images can be displayed immediately without sending a request to the server for resources.

Preloading classification

Out-of-order preloading

For example, when previewing a large number of images, or emojis, it cares when they are all loaded and then displayed together, and the order doesn’t matter.

Preloading of emojis
const srcList = ['src1'.'src2'.'src3'. ]function preLoad() {
    let count = ' ';
        for (let i = 0; i < emojiSrcs.length; i++) {
            var img = new Image()	
            img.src = srcList[i]  
            
            img.onload = img.onerror = function () {	// It will be executed whether the load succeeds or fails
                count++
                if (count == emojiSrcs.length - 1) {		// If all loads are completed
                    mask.style.display = "none";		// Hide the occlusion layer
                    emoji.style.display = "block";		/ / display emoji
                }
            }
        }
    }
 preLoad()
Copy the code

Ordered preloading

For comics, it’s not just about when they’re all loaded, it’s about ordering.

    // Use global variables to save counts
    var count = 0
    const emojiSrcs = ['src1'.'src2'.'src3'. ]function preLoad() {
        var img = new Image()
        img.src = emojiSrcs[count]
        count++
        // Both load success and load failure are executed
        img.onload = img.onerror = function () {
   		   if(count === emojiSrcs.length)
          	  return
           preLoad()
        }
    }
	preLoad()
	// When the first one is loaded, the second one is loaded, then the third one is loaded, so we can preload the second one and the third one while we preview the first one
	// In contrast to unordered loading, there is no need to wait until the use is finished to preview, and there is no need to preview the second image when the second image is not fully loaded, but the third or later image is loaded first.
Copy the code

Lazy loading of images

What is lazy loading

Lazy loading of images is waiting for the image to be seen by the user.

The opposite of preloading. Preloading is hard work, so to speak, done first and then all is well. And lazy loading is to need me to do, I will not be ready.

Lazy loading is simply show first, load later

What scenarios need lazy loading

  • electricity

We know that a lot of product displays are paginated requests. That is, we will see the end and then reload. But the screen only sees part of the requested page.

There will be a lot of images when e-commerce search products, but the individual image resources are not large. So it is suitable for lazy loading applications. Avoid unnecessary image loading and requests.

For example, when we buy something in a certain treasure, certain east, or certain evening, suppose we see a progress bar after the search, telling us that it is still loading. Or display a bunch of white space and then load it first (but may need to scroll down). However, we may choose the first store. Then everything else doesn’t need to be loaded.

  • Other pictures more scenes

This is different from the scene in the gallery online gallery. Images may primarily show more than just images. If a large number of articles are displayed, the articles have some illustrations.

Disadvantages of lazy loading

  • Need to monitor whether the picture is displayed, compare the consumption of visitor performance.
  • Images are loaded only when they are displayed. If the network is not so good there may be a period of blank

Image lazy loading method

The principle of

Use custom attributes to store the URL of the image on the image tag, with the SRC of the image empty or with another smaller image resource (hint loading)

Lazy loading of images mainly listens for the scroll event of the body or other element that holds the image and scrolls.

Each time the event is triggered, check whether the image is displayed through the associated API and properties.

If displayed, fill the URL into the SRC property and load the image. If no display is displayed, no operation is performed.

How to check whether the picture is displayed

It’s not hard to understand how lazy loading works. The key to lazy loading is how to detect whether the image handles the viewable area.

Here are two pictures to understand and learn.

  • ClientHeight: Height of view area

The viewable height can be obtained using window.innerWidth. But this property is not supported below Internet Explorer 9. So compatibility is written as:

let clientWidth=window.innerWidth|| document.documentElement.clientWidth|| document.body.clientWidth;

About this compatibility

  • offsetTop

The offset of the child image relative to the parent element. let offsetTop = imgNode.offsetTop

  • scrollTop

The height at which the top of the scroll element is rolled out of the display area. let scrollTop = scrollNode.scrollTop

** Note that this element must have a scroll bar, otherwise 0 **

If the scroll area is the entire page, that is, only THE HTML scroll bar appears, otherwise no scroll bar is set.

Then through the document. The documentElement. ScrollTop scrollTop to obtain the value

In general, we only examine the hidden parts of the entire page

As shown above: when scrollTop + clientHeight > offsetTop, the image is displayed or above the viewable area.

  • OffsetHeight: Width and height of the image node

You can set it by setting the height. Write to death.

or

element.clientHeight  // Add an inner margin to the content
element.offsetHeight  // Add an inner margin and a border to the content
Copy the code

As shown above: When offsetTop + offsetHeight > scrollTop, the image is in or below the viewable area.

Combine two graphs

if ( v.offsetTop < clientHeight + scrollTop &&  v.offsetTop + v.offsetHeight > scrollTop) {
  // The image is in the display area
}
Copy the code

demo

/ / lazy loading
// Parameter: id (#id), class name (.class), or tag name (img) of the image that needs to be preloaded
export default function lazyLoad(imgSelector) {

  const clientHeight = window.innerWidth || document.documentElement.clientWidth || document.body.clientWidth, // Compatible access
    scrollTop = document.documentElement.scrollTop;  // Get the height of the top where the page is rolled out

  let imgsNodes = document.querySelectorAll(imgSelector);  // Get the list of preloaded images


  // Iterate over the image to see if it is visible
  imgsNodes.forEach((v) = > {
    if (
      v.offsetTop < clientHeight + scrollTop &&
      v.offsetTop + v.offsetHeight > scrollTop
    ) {
      // Set the correct SRC

      // When in actual use
      // v.src = v.getAttribute("srcString");

      // Use a timer to simulate the loading time, so that you can see the effect of loading first.
      setTimeout(() = > {
        v.src = v.getAttribute("data-srcString");
      }, 800); }}); }Copy the code
<! DOCTYPEhtml>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="Width = device - width, initial - scale = 1.0">
    <title>Lazy loading</title>
</head>
<style>
    img {
        width: 300px;
        height: 300px;
        display: block;
        margin: 0 auto;
        border: 1px solid #ccc;
    }
</style>

<body>
    <div>
        <img data-srcString="Https://img1.baidu.com/it/u=3263944338, 3726722345 & FM = 26 & FMT = auto&gp = 0. JPG"
            src="https://z3.ax1x.com/2021/09/04/hguVeK.png">
        <img data-srcString="Https://img1.baidu.com/it/u=3263944338, 3726722345 & FM = 26 & FMT = auto&gp = 0. JPG"
            src="https://z3.ax1x.com/2021/09/04/hguVeK.png">
        <img data-srcString="Https://img1.baidu.com/it/u=3263944338, 3726722345 & FM = 26 & FMT = auto&gp = 0. JPG"
            src="https://z3.ax1x.com/2021/09/04/hguVeK.png">
        <img data-srcString="Https://img1.baidu.com/it/u=3263944338, 3726722345 & FM = 26 & FMT = auto&gp = 0. JPG"
            src="https://z3.ax1x.com/2021/09/04/hguVeK.png">
        <img data-srcString="Https://img1.baidu.com/it/u=3263944338, 3726722345 & FM = 26 & FMT = auto&gp = 0. JPG"
            src="https://z3.ax1x.com/2021/09/04/hguVeK.png">
        <img data-srcString="Https://img1.baidu.com/it/u=3263944338, 3726722345 & FM = 26 & FMT = auto&gp = 0. JPG"
            src="https://z3.ax1x.com/2021/09/04/hguVeK.png">
        <img data-srcString="Https://img1.baidu.com/it/u=3263944338, 3726722345 & FM = 26 & FMT = auto&gp = 0. JPG"
            src="https://z3.ax1x.com/2021/09/04/hguVeK.png">
        <img data-srcString="Https://img1.baidu.com/it/u=3263944338, 3726722345 & FM = 26 & FMT = auto&gp = 0. JPG"
            src="https://z3.ax1x.com/2021/09/04/hguVeK.png">
        <img data-srcString="Https://img1.baidu.com/it/u=3263944338, 3726722345 & FM = 26 & FMT = auto&gp = 0. JPG"
            src="https://z3.ax1x.com/2021/09/04/hguVeK.png">
    </div>
</body>

<script type="module">
    // Import the module
    import lazyLoad from './lazyLoad.js'
    // Use onload to avoid operating before the document is loaded
    window.onload  = function(){
        // call once to load photos that may be in the display area first
        lazyLoad('img')
        // Listen for scroll events
        window.addEventListener('scroll',lazyLoad.bind(this.'img'))  // Use bind() to pass arguments
    }
</script>
</html>
Copy the code

Lazy loading optimization

Earlier we addressed the downside of lazy loading, which is server-friendly but not browser friendly.

Because listening for scrolling events all the time, firing all the time is very performance consuming.

We can carry out anti-shake and throttling to reduce performance consumption. Improve fluency.

The throttle

The image has a certain width and height, and it’s not just a matter of moving a little bit to get the image node and walk through it.

Otherwise, only the code inside the HTML script tag is modified

<script type="module">
    import lazyLoad from './lazyLoad.js'

    window.onload  = function(){
        lazyLoad('img')  / / perform first

        let stop = true;  / / throttle valve
        
        function throttle (){  // throttling function
         if(stop){   // If throttled
            setTimeout(() = > {
                stop = false
                console.log('the throttling');
            }, 100);
            return 
         }
         stop=true
         lazyLoad('img');
         return;
        }

        window.addEventListener('scroll',throttle)  // Scroll executes the function to be throttled
    }
</script>
Copy the code

When you slide the scroll bar, you can see that the output throttling is alternating with the output throttling at execution time. A certain throttling effect is achieved.

Image stabilization

Why do it? Because there might be this scenario. We knew the image we wanted would slide down several pages. So the first few pages of pictures are not required to display.

Or we’ve already previewed it before, and I want to preview it later. So you don’t have to load the previous one.

In this case, anti-shake technology can be used.

Other unchanged, minor modifications in the original throttling function

    let stop = true;
    let timeID = ' ';   // Add a variable to hold the ID of the countdown timer

    function throttle (){
     if(stop){
        setTimeout(() = > {
            stop = false
        }, 100);

        return;
     }
     stop=true

     // Delete the previous timer
    clearTimeout(timeID)
	// Reset the countdown timer
    timeID = setTimeout(() = >{
        lazyLoad('img');
        return 
    },100)  // Delay loading for 0.1 seconds
    }   
Copy the code

But stabilization is not needed in most cases, unless the gap during the stabilization period is not too significant

Thanks for reading!

Refer to the article

Js image lazy loading principle

Js native implementation of high performance lazy loading (step by step analysis)