首页 > 代码库 > 实现图片的预加载和懒加载

实现图片的预加载和懒加载

延迟加载也称为惰性加载,即在长网页中延迟加载图像。用户滚动到它们之前,视口外的图像不会加载。这与图像预加载相反,在长网页上使用延迟加载将使网页加载更快。在某些情况下,它还可以帮助减少服务器负载。

那么延迟加载有什么好处:
1、提升用户的体验,避免出现卡顿现象。
2、有选择性地请求图片,减少服务器的压力和流量,减小浏览器的负担。

 实现方式:
1、首先将页面上的图片的 src 属性设为 loading.gif,而图片的真实路径则设置在 data-src 属性中,页面滚动的时候计算图片的位置与滚动的位置,当图片出现在浏览器视口内时,将图片的 src 属性设置为 data-src 的值,这样,就可以实现延迟加载

<!DOCTYPE html>
<html >
<head>
    <meta charset="UTF-8">
    <title>Lazyload 1</title>
    <style>
        img {
        display: block;
        margin-bottom: 50px;
        height: 200px;
    }
    </style>
</head>
<body>
    <img src="http://www.mamicode.com/images/loading.gif" data-src="http://www.mamicode.com/images/1.png">
    <img src="http://www.mamicode.com/images/loading.gif" data-src="http://www.mamicode.com/images/2.png">
    <img src="http://www.mamicode.com/images/loading.gif" data-src="http://www.mamicode.com/images/3.png">
    <img src="http://www.mamicode.com/images/loading.gif" data-src="http://www.mamicode.com/images/4.png">
    <img src="http://www.mamicode.com/images/loading.gif" data-src="http://www.mamicode.com/images/5.png">
    <img src="http://www.mamicode.com/images/loading.gif" data-src="http://www.mamicode.com/images/6.png">
    <img src="http://www.mamicode.com/images/loading.gif" data-src="http://www.mamicode.com/images/7.png">
    <img src="http://www.mamicode.com/images/loading.gif" data-src="http://www.mamicode.com/images/8.png">
    <img src="http://www.mamicode.com/images/loading.gif" data-src="http://www.mamicode.com/images/9.png">
    <img src="http://www.mamicode.com/images/loading.gif" data-src="http://www.mamicode.com/images/10.png">
    <img src="http://www.mamicode.com/images/loading.gif" data-src="http://www.mamicode.com/images/11.png">
    <img src="http://www.mamicode.com/images/loading.gif" data-src="http://www.mamicode.com/images/12.png">
    <script>
        function lazyload() {
        var images = document.getElementsByTagName(‘img‘);
        var len    = images.length;
        var n      = 0;      //存储图片加载到的位置,避免每次都从第一张图片开始遍历        
        return function() {
        var seeHeight = document.documentElement.clientHeight;
        var scrollTop = document.documentElement.scrollTop || document.body.scrollTop;
        for(var i = n; i < len; i++) {
            if(images[i].offsetTop < seeHeight + scrollTop) {
                if(images[i].getAttribute(‘src‘) === ‘images/loading.gif‘) {
                 images[i].src = images[i].getAttribute(‘data-src‘);
            }
            n = n + 1;
             }
        }
        }
    }
    var loadImages = lazyload();
    loadImages();          //初始化首页的页面图片
    window.addEventListener(‘scroll‘, loadImages, false);
    </script>
</body>
</html>

不断滑动页面时,图片延迟加载。 image 的 offsetTop 与 seeHeight + scrollTop 的大小,当小于时则说明图片已经出现过在视口中,这时候继续判断图片是否已经替换过,如果没有替换过,则进行替换。

上面的代码是没什么问题,但是性能偏差。如果直接将函数绑定在 scroll 事件上,当页面滚动时,函数会被高频触发,这非常影响浏览器的性能。我粗略地估计一下,当简单地滚动一下页面,函数至少触发了十来次,这显然是十分没必要的。

2、所以在做事件绑定的时候,可以对 lazyload 函数进行函数节流(throttle)与函数去抖(debounce)处理。

Debounce:一部电梯停在某一个楼层,当有一个人进来后,20秒后自动关门,这20秒的等待期间,又一个人按了电梯进来,这20秒又重新计算,直到电梯关门那一刻才算是响应了事件。
Throttle:好比一台自动的饮料机,按拿铁按钮,在出饮料的过程中,不管按多少这个按钮,都不会连续出饮料,中间按钮的响应会被忽略,必须要等这一杯的容量全部出完之后,再按拿铁按钮才会出下一杯。

技术分享
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Lazyload 2</title>
    <style>
    img {
        display: block;
        margin-bottom: 50px;
        height: 200px;
    }
    </style>
</head>
<body>
    <img src="http://www.mamicode.com/images/loading.gif" data-src="http://www.mamicode.com/images/1.png">
    <img src="http://www.mamicode.com/images/loading.gif" data-src="http://www.mamicode.com/images/2.png">
    <img src="http://www.mamicode.com/images/loading.gif" data-src="http://www.mamicode.com/images/3.png">
    <img src="http://www.mamicode.com/images/loading.gif" data-src="http://www.mamicode.com/images/4.png">
    <img src="http://www.mamicode.com/images/loading.gif" data-src="http://www.mamicode.com/images/5.png">
    <img src="http://www.mamicode.com/images/loading.gif" data-src="http://www.mamicode.com/images/6.png">
    <img src="http://www.mamicode.com/images/loading.gif" data-src="http://www.mamicode.com/images/7.png">
    <img src="http://www.mamicode.com/images/loading.gif" data-src="http://www.mamicode.com/images/8.png">
    <img src="http://www.mamicode.com/images/loading.gif" data-src="http://www.mamicode.com/images/9.png">
    <img src="http://www.mamicode.com/images/loading.gif" data-src="http://www.mamicode.com/images/10.png">
    <img src="http://www.mamicode.com/images/loading.gif" data-src="http://www.mamicode.com/images/11.png">
    <img src="http://www.mamicode.com/images/loading.gif" data-src="http://www.mamicode.com/images/12.png">
    <script>
    function throttle(fn, delay, atleast) {
        var timeout = null,
        startTime = new Date();
        return function() {
        var curTime = new Date();
        clearTimeout(timeout);
        if(curTime - startTime >= atleast) {
            fn();
            startTime = curTime;
        }else {
            timeout = setTimeout(fn, delay);
        }
        }
    }
    function lazyload() {
        var images = document.getElementsByTagName(‘img‘);
        var len    = images.length;
        var n      = 0;      //存储图片加载到的位置,避免每次都从第一张图片开始遍历        
        return function() {
        var seeHeight = document.documentElement.clientHeight;
        var scrollTop = document.documentElement.scrollTop || document.body.scrollTop;
        for(var i = n; i < len; i++) {
            if(images[i].offsetTop < seeHeight + scrollTop) {
                if(images[i].getAttribute(‘src‘) === ‘images/loading.gif‘) {
                 images[i].src = images[i].getAttribute(‘data-src‘);
                }
            n = n + 1;
             }
        }
        }
    }
    var loadImages = lazyload();
    loadImages();          //初始化首页的页面图片
    window.addEventListener(‘scroll‘, throttle(loadImages, 500, 1000), false);
    </script>
</body>
</html>
View Code

设置了 500ms 的延迟,和 1000ms 的间隔,当超过 1000ms 未触发该函数,则立即执行该函数,不然则延迟 500ms 执行该函数。

 

预加载图片是提高用户体验的一个很好方法。图片预先加载到浏览器中,访问者便可顺利地在你的网站上冲浪,并享受到极快的加载速度。这对图片画廊及图片占据很大比例的网站来说十分有利,它保证了图片快速、无缝地发布,也可帮助用户在浏览你网站内容时获得更好的用户体验。

1、用CSS和JavaScript实现预加载

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

将这三个ID选择器应用到(X)HTML元素中,我们便可通过CSS的background属性将图片预加载到屏幕外的背景上。只要这些图片的路径保持不变,当它们在Web页面的其他地方被调用时,浏览器就会在渲染过程中使用预加载(缓存)的图片。简单、高效,不需要任何JavaScript。
该方法虽然高效,但仍有改进余地。使用该法加载的图片会同页面的其他内容一起加载,增加了页面的整体加载时间。为了解决这个问题,我们增加了一些JavaScript代码,来推迟预加载的时间,直到页面加载完毕。代码如下:

function preloader() {
    if (document.getElementById) {
        document.getElementById("preload-01").style.background = "url() no-repeat -9999px -9999px";
        document.getElementById("preload-02").style.background = "url() no-repeat -9999px -9999px";
        document.getElementById("preload-03").style.background = "url() no-repeat -9999px -9999px";
    }
}
function addLoadEvent(func) {
    var oldonload = window.onload;   //获得window.onload的内容
    if (typeof window.onload != ‘function‘) { //判断windown.onload是否为函数。如果不是函数,则执行自己的函数,如果是函数,则先执行已经赋值的函数,再执行自己的函数
        window.onload = func;
    } else {
        window.onload = function() {
            if (oldonload) {
                oldonload();
            }
            func();
        }
    }
}
addLoadEvent(preloader);

2、纯JavaScript实现,与Css实现相比,会减少时间

function preloader() {
    if (document.images) {
        var img1 = new Image();
        var img2 = new Image();
        var img3 = new Image();
        img1.src = ";;
        img2.src = http://www.mamicode.com/";;
        img3.src = ";;
    }
}
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);
 

3、使用Ajax实现预加载

上面所给出的方法似乎不够酷,那现在来看一个使用Ajax实现图片预加载的方法。该方法利用DOM,不仅仅预加载图片,还会预加载CSS、JavaScript等相关的东西。使用Ajax,比直接使用JavaScript,优越之处在于JavaScript和CSS的加载不会影响到当前页面。该方法简洁、高效。

window.onload = function() {
    setTimeout(function() {
        // XHR to request a JS and a CSS
        var xhr = new XMLHttpRequest();
        xhr.open(‘GET‘, ‘;);
        xhr.send(‘‘);
        xhr = new XMLHttpRequest();
        xhr.open(‘GET‘, ‘;);
        xhr.send(‘‘);
        // preload image
        new Image().src = "http://www.mamicode.com/;;
    }, 1000);
};
 

上面代码预加载了“preload.js”、“preload.css”和“preload.png”。1000毫秒的超时是为了防止脚本挂起,而导致正常页面出现功能问题。

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 = ";;
 
        // a new JS
        var js  = document.createElement("script");
        js.type = "text/javascript";
        js.src  = "http://www.mamicode.com/;;
 
        // preload JS and CSS
        head.appendChild(css);
        head.appendChild(js);
 
        // preload image
        new Image().src = http://www.mamicode.com/";;
 
    }, 1000);
 
};
 

 

实现图片的预加载和懒加载