Bootstrap

网页延迟加载范例

说明:主要内容转自网络,但原文地址丢失,有异议请留言提醒。

定义:延迟加载也称为惰性加载,即在长网页中延迟加载图像。用户滚动到它们之前,视口外的图像不会加载。这与图像预加载相反,在长网页上使用延迟加载将使网页加载更快。在某些情况下,它还可以帮助减少服务器负载。
举个例子来说明,当打开淘宝首页的时候,只有在浏览器窗口里的图片才会被加载,当你滚动首页向下滑的时候,进入视口内的图片才会被加载,而其它从未进入视口的图像不会也不会加载。

那么延迟加载有什么好处:

1、首先它能提升用户的体验,试想一下,如果打开页面的时候就将页面上所有的图片全部获取加载,如果图片数量较大,对于用户来说简直就是灾难,会出现卡顿现象,影响用户体验。
2、有选择性地请求图片,这样能明显减少了服务器的压力和流量,也能够减小浏览器的负担。
那么下面就介绍延迟加载的两种实现方式:

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

下面是具体的实现代码:(代码放在附件中,把第二部分那个代码删除后就是第一种的代码)

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

实现的效果:不断滑动页面时,图片延迟加载

你可以拷贝我的代码去进行实验,但是请确保 HTML 同目录下有 images 目录并且含有 1~12.png 和 loading.gif。

需要提及的是变量 n 是用来保存已经加载的图片数量,避免每次都从第一张图片开始遍历,提升性能。上面的代码用到了 JS 闭包的知识,如果你不太熟悉的话,可以自行百度一下。

第二种
上面的代码是没什么问题,但是性能偏差。如果直接将函数绑定在 scroll 事件上,当页面滚动时,函数会被高频触发,这非常影响浏览器的性能。我粗略地估计一下,当简单地滚动一下页面,函数至少触发了十来次,这显然是十分没必要的。
所以在做事件绑定的时候,可以对 lazyload 函数进行函数节流(throttle)与函数去抖(debounce)处理。
这里我并不再另外介绍这两种方案,如果你想了解的话可以阅读:JS魔法堂:函数节流(throttle)与函数去抖(debounce) – ^_^肥仔John – 博客园
简单说来:

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

      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);
            }
          }
      }

        // window.addEventListener('scroll', loadImages, false);

        window.addEventListener('scroll', throttle(loadImages, 50, 100), false);  
        // throttle()  设置了 500ms 的延迟,和 1000ms 的间隔,当超过 1000ms 未触发该函数,则立即执行该函数,不然则延迟 500ms 执行该函数。

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

实现效果:可以看出有一定的延迟。
 

源码:测试过,但是需要同目录下有images文件夹和相关图片

<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <title>页面下拉到图片位置后才加载图片</title>
    <style>
        img {  
          display: block;
          margin-bottom: 50px;
          height: 400px;
        }
    </style>
</head>

<body>
    <div>
        <img src="./images/loading.gif" data-src="./images/01.jpg">
        <img src="./images/loading.gif" data-src="./images/02.jpg">
        <img src="./images/loading.gif" data-src="./images/03.jpg">
        <img src="./images/loading.gif" data-src="./images/04.jpg">
        <img src="./images/loading.gif" data-src="./images/05.jpg">
        <img src="./images/loading.gif" data-src="./images/06.jpg">
        <img src="./images/loading.gif" data-src="./images/07.jpg">
        <img src="./images/loading.gif" data-src="./images/08.jpg">
        <img src="./images/loading.gif" data-src="./images/09.jpg">
        <img src="./images/loading.gif" data-src="./images/10.jpg">
        <img src="./images/loading.gif" data-src="./images/11.jpg">
        <img src="./images/loading.gif" data-src="./images/12.jpg">
    </div>
    <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', loadImages, false);

        window.addEventListener('scroll', throttle(loadImages, 50, 100), false);  
        // throttle()  设置了 500ms 的延迟,和 1000ms 的间隔,当超过 1000ms 未触发该函数,则立即执行该函数,不然则延迟 500ms 执行该函数。
    </script>
</body>

</html>