Image lazy loading is a way to optimize web page performance, which can greatly improve user experience. At the same time, it is easy to be asked by the interviewer about its implementation and principle in the interview. I have been in touch with it for a long time. Since I haven’t written an article in recent months, I want to take this opportunity to review it

Why lazy loading?

In some pictures more websites (such as a large e-commerce sites) picture is very much, if we are just at the moment of open web pages load all images from the web site, is likely to cause caton and bad phenomenon, user experience extremely poor, if encounter grumpy friend believes directly backhand is a Ctrl + W. Because really a lot of images, a moment load all images from the web browser in a short period of time not to deal with, but we open the website that moment is only able to see the pictures inside the viewport, this time to load the web page at the bottom of the picture is very waste of resources and there is no need to, so in this case use lazy loading technology is particularly necessary.

Lazy loading implementation principle

The principle of lazy loading is actually very simple, which is to pre-place the real SRC of the image in our custom attributes (such as data-src). When the image appears in our viewport range, then assign the data-src value to the SRC attribute to complete the image loading.

// when the page is initialized<img data-src="https://img11.360buyimg.com/pop/s590x470.jpg.webp" />// When the image appears in the viewport range<img data-src="https://img11.360buyimg.com/pop/s590x470.jpg.webp" src="https://img11.360buyimg.com/pop/s590x470.jpg.webp"/>
Copy the code

One of the things you can do is initialize without the IMG tagsrcProperty, because as long as there issrcProperty, the browser will perform a request to download the resource it points to and apply it to the document, without adding some performance improvements

The specific implementation

Based on the idea explained in front, we hand write a lazy load

Create a new lazyload. HTML file, initialize the DOM structure and set the corresponding style

<! DOCTYPEhtml>
<html>
<head>
  <title>lazy load</title>
  <style>
    .img {
      width: 220px;
      height: 220px;
      background-color: #ccc;
      margin-bottom: 40px;
      margin-left: 50px;
    }

    .pic {
      width: 100%;
      height: 100%;
    }
  </style>
</head>

<body>
  <div class="container">
  <! -- Put the real SRC in data-src first -->
    <div class="img">
      <img class="pic" alt="Loading..." data-src="https://img10.360buyimg.com/n7/jfs/t1/183679/11/2189/143829/6091f5d8E933e7ad1/e3e2001666f2ce7b.jpg" />
    </div>
    <div class="img">
      <img class="pic" alt="Loading..." data-src="https://img12.360buyimg.com/n7/jfs/t1/192682/11/617/163213/608b887aEddbbbee3/9570466a90d02f79.jpg" />
    </div>
    <div class="img">
      <img class="pic" alt="Loading..." data-src="https://img14.360buyimg.com/n7/jfs/t1/156161/35/18802/268242/60641d96Eca3dee7f/4a32070a19deb4f5.jpg" />
    </div>
    <div class="img">
      <img class="pic" alt="Loading..." data-src="https://img10.360buyimg.com/n7/jfs/t1/130179/12/9273/167054/5f5468edE9d4ecd9c/39f7520d9f76b695.jpg" />
    </div>
    <div class="img">
      <img class="pic" alt="Loading..." data-src="https://img14.360buyimg.com/n7/jfs/t1/100888/13/13132/105320/5e5533c6Ea8daa487/f95d7ba4da5581c5.jpg" />
    </div>
    <div class="img">
      <img class="pic" alt="Loading..." data-src="https://img10.360buyimg.com/n7/jfs/t1/173986/31/8862/291849/6098d6d0E26c55012/c2144f6e074556d2.jpg" />
    </div>
    <div class="img">
      <img class="pic" alt="Loading..." data-src="https://img10.360buyimg.com/n7/jfs/t1/110754/4/12605/101916/5ee43244E6fbf9433/c42fb5e3f9558a59.jpg" />
    </div>
    <div class="img">
      <img class="pic" alt="Loading..." data-src="https://img10.360buyimg.com/n7/jfs/t1/148370/31/1084/45848/5eedc2eeEfdc2cd46/f3c3a6f0bd7998be.jpg" />
    </div>
    <div class="img">
      <img class="pic" alt="Loading..." data-src="https://img10.360buyimg.com/n7/jfs/t1/165930/8/7273/171076/602fd5dfE65a52775/ee27074b7037c020.jpg" />
    </div>
    <div class="img">
      <img class="pic" alt="Loading..." data-src="https://img13.360buyimg.com/n7/jfs/t1/190093/28/117/193777/60867822Ea949fbec/6fe51b122d0fdc5a.jpg" />
    </div>
    <div class="img">
      <img class="pic" alt="Loading..." data-src="https://img14.360buyimg.com/n7/jfs/t1/119501/15/6768/115886/5eca6c36Eb3541dc9/2f4534173878a23c.jpg" />
    </div>
  </div>
  </body>
  </html>
Copy the code

Followed by JS part, we need to know in advance some value, one is current the viewport height of the browser window, the other one is each image distance is the distance of the top viewport, because only when the distance images at the top of the distance is less than our viewport height, then on behalf of the picture has emerged within the scope of our viewport.

Gets the browser viewport height

We usually use to obtain the height of the viewing area window. The innerHeight can get, of course, if need to be compatible with low version of Internet explorer browser, you can use the document. The documentElement. ClientHeight to obtain, here we do a compatibility processing

const viewPortHeight = window.innerHeight || document.documentElement.clientHeight
Copy the code

Gets the distance of the image from the top

GetBoundingClientRect () = getBoundingClientRect() = getBoundingClientRect() = getBoundingClientRect() = getBoundingClientRect(

At this point, we have the two values we need, so let’s go straight to the code:

// Get all the images
const imgList = document.querySelectorAll('img')
// Record which image is currently displayed
let index = 0;
function lazyload() {
  // Get the height of the browser viewport, which is written inside the function to take into account changes in the browser window size
  const viewPortHeight = window.innerHeight || document.documentElement.clientHeight
  for (let i = index; i < imgList.length; i++) {
    // Subtract the height from the top of the image to the top of the viewable area
    const distance = viewPortHeight - imgList[i].getBoundingClientRect().top;
    // If the viewport height is greater than or equal to the height from the top of the element to the top of the viewport, the image is in viewport range
    if (distance >= 0) {
      // Assign an actual SRC value to the image to display the image
      imgList[i].src = imgList[i].getAttribute('data-src');
      // The first I image has been loaded, next time from the first I +1 check whether need to display
      index = i + 1; }}}// Define an anti-shake function
function debounce(fn, delay = 500) {
  let timer = null;
  return function (. args) {
    if (timer) clearTimeout(timer);
    timer = setTimeout(() = > {
      fn.apply(this, args);
    }, delay);
  };
}

// When the page is loaded, perform a lazyLoad to render the image in the viewport of the page opened for the first time
window.onload = lazyload;
// Listen for Scroll events. In order to prevent frequent calls, use the anti-shake function to optimize
window.addEventListener("scroll", debounce(lazyload, 600));
// Recalculate when the browser window size changes
window.addEventListener("resize", debounce(lazyload, 600));

Copy the code

The final result

Here is our picture lazy loading finished, the following is the effect map, like the friend trouble point like it