Performance optimization and practice of front-end picture rendering - lazy loading of pictures

Posted by yousaf931 on Tue, 25 Jan 2022 12:43:30 +0100

preface

For the home page APP with a large number of pictures, you need to add a large number of pictures when opening the commodity display page. In this scenario, if you directly load the full amount, it will inevitably lead to excessive page performance consumption, white screen or Caton, and the user experience is very bad. Do users really need us to display all the pictures together? In fact, it's not. What users see is the content of the browser's visual area. Therefore, from this situation, we can make some optimization to display only the pictures in the user's visual area. When the user triggers scrolling, we can request to display them to the user

Implementation of image lazy loading:

  1. Add a custom attribute to all img tags that need to be displayed: Data src. At the same time, do not set the src attribute. The value of data src is the image url.

  2. After the page is loaded, we need to get the element set of all the pictures that need to be loaded lazily, judge whether it is in the visual area, and if it is in the visual area, reset the src attribute value of the element to the address of the real picture.

  3. Judgment of visual area: compare the top value of the getBoundingClientRect attribute of the element with the clientHeight of the page. If the top value is less than clientHeight, it indicates that the element appears in the visual area.

  4. When the user scrolls the window, you should judge whether the element appears in the visual area through the BoundingClientRect attribute of each element. If it is in the visual area, the rendered image is displayed in the visual area.

Implementation of lazy loading:

<!-- Load pictures only in the visualization area -->
<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>

<body> <img style="width: 250px;height: 250px;background-color: grey; display: block;" data-src="./img/test01.PNG"
        alt=""> <img style="width: 250px;height: 250px;background-color: grey; display: block;"
        data-src="./img/test01.PNG" alt=""> <img
        style="width: 250px;height: 250px;background-color: grey; display: block;" data-src="./img/test01.PNG" alt="">
    <img style="width: 250px;height: 250px;background-color: grey; display: block;" data-src="./img/test01.PNG" alt="">
    <img style="width: 250px;height: 250px;background-color: grey; display: block;" data-src="./img/test01.PNG" alt="">
    <img style="width: 250px;height: 250px;background-color: grey; display: block;" data-src="./img/test01.PNG" alt="">
    <img style="width: 250px;height: 250px;background-color: grey; display: block;" data-src="./img/test01.PNG" alt="">
    <img style="width: 250px;height: 250px;background-color: grey; display: block;" data-src="./img/test01.PNG" alt="">
    <img style="width: 250px;height: 250px;background-color: grey; display: block;" data-src="./img/test01.PNG" alt="">
    <img style="width: 250px;height: 250px;background-color: grey; display: block;" data-src="./img/test01.PNG" alt="">
    <img style="width: 250px;height: 250px;background-color: grey; display: block;" data-src="./img/test01.PNG" alt="">
    <img style="width: 250px;height: 250px;background-color: grey; display: block;" data-src="./img/test01.PNG" alt="">
</body>
<script>
    var viewHeight = document.documentElement.clientHeight; // Height of visualization area    
    var viewWidth = document.documentElement.clientWidth; // Width of visualization area    
    function lazyload() { //Get all the pictures to be loaded lazily        
        let eles = document.querySelectorAll('img[data-src]'); // Get the attribute with data Src in the attribute name        
        console.log('Get all the information', eles)
        Array.prototype.forEach.call(eles, function (item, index) {
            let rect;
            if (item.dataset.src === '') {
                return;
            }
            rect = item.getBoundingClientRect(); // Returns the size of the element and its position relative to the viewport            
            console.log('Returns the size of the element and its position relative to the viewport', rect) //As soon as the picture enters the visual area, it is loaded dynamically            
            if (rect.bottom >= 0 && rect.top < viewHeight) {
                ! function () {
                    let img = new Image();
                    img.src = item.dataset.src;
                    img.onload = function () {
                        item.src = img.src;
                    }
                    item.removeAttribute('data-src');
                }();
            }
        })
    }
    lazyload();
</script>

</html>

In the above code, we have initially completed the lazy loading of pictures, but we all know that the event of scroll will be triggered many times when the user scrolls the mouse, which will also lead to a sharp decline in our performance. Therefore, this leads to our hybrid anti shake function to optimize our performance:

function debounce(fn, gapTime) {
        let timer = null;
        return function () {
            if (timer) {
                clearTimeout(timer);
                timer = null;
            }
            timer = setTimeout(function () {
                fn();
            }, gapTime)
        }
    }

Finally, post the complete code:

<!-- Load pictures only in the visualization area -->
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>
    <img id="img" style="width: 250px;height: 250px;background-color: grey; display: block;" data-src="./img/test01.PNG" alt="">
    <img style="width: 250px;height: 250px;background-color: grey; display: block;" data-src="./img/test01.PNG" alt="">
    <img style="width: 250px;height: 250px;background-color: grey; display: block;" data-src="./img/test01.PNG" alt="">
    <img style="width: 250px;height: 250px;background-color: grey; display: block;" data-src="./img/test01.PNG" alt="">
    <img style="width: 250px;height: 250px;background-color: grey; display: block;" data-src="./img/test01.PNG" alt="">
    <img style="width: 250px;height: 250px;background-color: grey; display: block;" data-src="./img/test01.PNG" alt="">
    <img style="width: 250px;height: 250px;background-color: grey; display: block;" data-src="./img/test01.PNG" alt="">
    <img style="width: 250px;height: 250px;background-color: grey; display: block;" data-src="./img/test01.PNG" alt="">
    <img style="width: 250px;height: 250px;background-color: grey; display: block;" data-src="./img/test01.PNG" alt="">
    <img style="width: 250px;height: 250px;background-color: grey; display: block;" data-src="./img/test01.PNG" alt="">
    <img style="width: 250px;height: 250px;background-color: grey; display: block;" data-src="./img/test01.PNG" alt="">
    <img style="width: 250px;height: 250px;background-color: grey; display: block;" data-src="./img/test01.PNG" alt="">
</body>
<script>
    var viewHeight = document.documentElement.clientHeight;  // Height of visualization area
    var viewWidth = document.documentElement.clientWidth; // Width of visualization area
    console.log('Height of visualization area', viewHeight)
    console.log('Width of visualization area', viewWidth)
    let imgDom = document.getElementById('img');
    console.log(window.getComputedStyle(imgDom, null).color);        // To get all the

    function lazyload () {
        //Get all pictures to be loaded lazily
        let eles = document.querySelectorAll('img[data-src]'); // Get the attribute with data Src in the attribute name
        console.log('Get all the information', eles)
        Array.prototype.forEach.call(eles, function(item, index) {
            let rect;
            if(item.dataset.src === '') {
                return;
            }

            rect = item.getBoundingClientRect();  // Returns the size of the element and its position relative to the viewport
            console.log('Returns the size of the element and its position relative to the viewport', rect)

            //As soon as the picture enters the visual area, it is loaded dynamically
            if(rect.bottom >= 0 && rect.top < viewHeight) {
                !function () {
                    let img = new Image();
                    img.src = item.dataset.src;
                    img.onload = function () {
                        item.src = img.src;
                    }
                    item.removeAttribute('data-src');
                }();
            }
        })
    }
    lazyload();

    // Add scroll event to trigger picture loading
    document.addEventListener('scroll', debounce(lazyload, 500), false);

    // Continuous optimization through function anti chattering:
    function debounce(fn, gapTime) {
        let timer = null;
        return function() {
            if(timer) {
                clearTimeout(timer);
                timer = null;
            }
            timer = setTimeout(function() {
                fn();
            }, gapTime)
        }
    }
 
</script>
</html>

Nuggets link:

  • https://juejin.cn/post/6977945074885722126

Topics: Javascript Front-end Optimize