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

举个例子来说明,当打开淘宝首页的时候,只有在浏览器窗口里的图片才会被加载,当你滚动首页向下滑的时候,进入视口内的图片才会被加载,而其它从未进入视口的图像不会也不会加载。

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

1、首先它能提升用户的体验,试想一下,如果打开页面的时候就将页面上所有的图片全部获取加载,如果图片数量较大,对于用户来说简直就是灾难,会出现卡顿现象,影响用户体验。

2、有选择性地请求图片,这样能明显减少了服务器的压力和流量,也能够减小浏览器的负担。

那么下面就介绍延迟加载的三种实现方式:

第一种

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

下面是具体的实现代码:

<!DOCTYPE
html>
<html
lang=
"en">
<head>
    <meta
charset=
"UTF-8">
    <title>Lazyload
1</title>
    <style>
        img
{
        display:
block;
        margin-bottom:
50px;
        height:
200px;
    }
    </style>
</head>
<body>
    <img
src=
"images/loading.gif"data-src="images/1.png">
    <img
src=
"images/loading.gif"data-src="images/2.png">
    <img
src=
"images/loading.gif"data-src="images/3.png">
    <img
src=
"images/loading.gif"data-src="images/4.png">
    <img
src=
"images/loading.gif"data-src="images/5.png">
    <img
src=
"images/loading.gif"data-src="images/6.png">
    <img
src=
"images/loading.gif"data-src="images/7.png">
    <img
src=
"images/loading.gif"data-src="images/8.png">
    <img
src=
"images/loading.gif"data-src="images/9.png">
    <img
src=
"images/loading.gif"data-src="images/10.png">
    <img
src=
"images/loading.gif"data-src="images/11.png">
    <img
src=
"images/loading.gif"data-src="images/12.png">
    <script>
        functionlazyload()
{
        varimages
= document.getElementsByTagName(
'img');
        varlen   
= images.length;
        varn     
= 0;     
//存储图片加载到的位置,避免每次都从第一张图片开始遍历      
        returnfunction()
{
        varseeHeight
= document.documentElement.clientHeight;
        varscrollTop
= document.documentElement.scrollTop || document.body.scrollTop;
        for(vari
= 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;
             }
        }
        }
    }
    varloadImages
= lazyload();
    loadImages();         //初始化首页的页面图片
    window.addEventListener('scroll',
loadImages,
false);
    </script>
</body>
</html>

比较 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 处理后的代码:

<!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=
"images/loading.gif"data-src="images/1.png">
    <img
src=
"images/loading.gif"data-src="images/2.png">
    <img
src=
"images/loading.gif"data-src="images/3.png">
    <img
src=
"images/loading.gif"data-src="images/4.png">
    <img
src=
"images/loading.gif"data-src="images/5.png">
    <img
src=
"images/loading.gif"data-src="images/6.png">
    <img
src=
"images/loading.gif"data-src="images/7.png">
    <img
src=
"images/loading.gif"data-src="images/8.png">
    <img
src=
"images/loading.gif"data-src="images/9.png">
    <img
src=
"images/loading.gif"data-src="images/10.png">
    <img
src=
"images/loading.gif"data-src="images/11.png">
    <img
src=
"images/loading.gif"data-src="images/12.png">
    <script>
    functionthrottle(fn,
delay, atleast) {
        vartimeout
=
null,
        startTime
=
newDate();
        returnfunction()
{
        varcurTime
=
newDate();
        clearTimeout(timeout);
        if(curTime
- startTime >= atleast) {
            fn();
            startTime
= curTime;
        }else{
            timeout
= setTimeout(fn, delay);
        }
        }
    }
    functionlazyload()
{
        varimages
= document.getElementsByTagName(
'img');
        varlen   
= images.length;
        varn     
= 0;     
//存储图片加载到的位置,避免每次都从第一张图片开始遍历      
        returnfunction()
{
        varseeHeight
= document.documentElement.clientHeight;
        varscrollTop
= document.documentElement.scrollTop || document.body.scrollTop;
        for(vari
= 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;
             }
        }
        }
    }
    varloadImages
= lazyload();
    loadImages();         //初始化首页的页面图片
    window.addEventListener('scroll',
throttle(loadImages, 500, 1000),
false);
    </script>
</body>
</html>

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

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



参考链接:实现图片懒加载(lazyload)

第三种: 使用 IntersectionObserver API

目前有一个新的 IntersectionObserver API,可以自动”观察”元素是否可见,Chrome 51+ 已经支持。

这里不过多介绍 IntersectionObserver API 的详细使用,感兴趣可以另外阅读下面的文章:

IntersectionObserver API 使用教程

Intersection Observer API

实现代码:简洁,但是浏览器尚未全部实现。

<!DOCTYPE
html>
<html
lang=
"en">
<head>
    <meta
charset=
"UTF-8">
    <title>Lazyload
3</title>
    <style>
        img
{
        display:
block;
        margin-bottom:
50px;
        width:
800px;
        }
    </style>
</head>
<body>
    <img
src=
"images/loading.gif"data-src="images/1.png">
    <img
src=
"images/loading.gif"data-src="images/2.png">
    <img
src=
"images/loading.gif"data-src="images/3.png">
    <img
src=
"images/loading.gif"data-src="images/4.png">
    <img
src=
"images/loading.gif"data-src="images/5.png">
    <img
src=
"images/loading.gif"data-src="images/6.png">
    <img
src=
"images/loading.gif"data-src="images/7.png">
    <img
src=
"images/loading.gif"data-src="images/8.png">
    <img
src=
"images/loading.gif"data-src="images/9.png">
    <img
src=
"images/loading.gif"data-src="images/10.png">
    <img
src=
"images/loading.gif"data-src="images/11.png">
    <img
src=
"images/loading.gif"data-src="images/12.png">
    <script>
    functionquery(selector)
{
        returnArray.from(document.querySelectorAll(selector));
    }
    vario
=
newIntersectionObserver(function(items)
{
        items.forEach(function(item)
{
        vartarget
= item.target;
        if(target.getAttribute('src')
==
'images/loading.gif')
{
            target.src
= target.getAttribute(
'data-src');
        }
        })
    });
    query('img').forEach(function(item)
{
        io.observe(item);
    });
    </script>
</body>
</html>

1、IntersectionObserver 传入一个回调函数,当其观察到元素集合出现时候,则会执行该函数。

2、io.observe 即要观察的元素,要一个个添加才可以。

3、io 管理的是一个数组,当元素出现或消失的时候,数组添加或删除该元素,并且执行该回调函数。

实现效果:

原文地址:https://zhuanlan.zhihu.com/p/25455672

延迟加载(Lazyload)三种实现方式的更多相关文章

  1. MyBatis 延迟加载的三种加载方式深入,你get了吗?

    延迟加载 延迟加载对主对象都是直接加载,只有对关联对象是延迟加载. 延迟加载可以减轻数据库的压力, 延迟加载不可是一条SQL查询多表信息,这样构不成延迟加载,会形成直接加载. 延迟加载分为三种类型: ...

  2. 通过三个DEMO学会SignalR的三种实现方式

    一.理解SignalR ASP .NET SignalR 是一个ASP .NET 下的类库,可以在ASP .NET 的Web项目中实现实时通信(即:客户端(Web页面)和服务器端可以互相实时的通知消息 ...

  3. Hive metastore三种配置方式

    http://blog.csdn.net/reesun/article/details/8556078 Hive的meta数据支持以下三种存储方式,其中两种属于本地存储,一种为远端存储.远端存储比较适 ...

  4. django 模板语法和三种返回方式

    模板 for循环 {% for athlete in athlete_list %} <li>{{ athlete.name }}</li> {% endfor %} if语句 ...

  5. js的三种继承方式及其优缺点

    [转] 第一种,prototype的方式: //父类 function person(){ this.hair = 'black'; this.eye = 'black'; this.skin = ' ...

  6. spring ioc三种注入方式

    spring ioc三种注入方式 IOC ,全称 (Inverse Of Control) ,中文意思为:控制反转 什么是控制反转? 控制反转是一种将组件依赖关系的创建和管理置于程序外部的技术. 由容 ...

  7. Map三种遍历方式

    Map三种遍历方式 package decorator; import java.util.Collection; import java.util.HashMap; import java.util ...

  8. php 递归函数的三种实现方式

    递归函数是我们常用到的一类函数,最基本的特点是函数自身调用自身,但必须在调用自身前有条件判断,否则无限无限调用下去.实现递归函数可以采取什么方式呢?本文列出了三种基本方式.理解其原来需要一定的基础知识 ...

  9. JSON的三种解析方式

    一.什么是JSON? JSON是一种取代XML的数据结构,和xml相比,它更小巧但描述能力却不差,由于它的小巧所以网络传输数据将减少更多流量从而加快速度. JSON就是一串字符串 只不过元素会使用特定 ...

随机推荐

  1. 滑动窗口(poj,线段树维护区间最值)

    题目描述 现在有一堆数字共N个数字(N<=10^6),以及一个大小为k的窗口.现在这个从左边开始向右滑动,每次滑动一个单位,求出每次滑动后窗口中的最大值和最小值. 例如: The array i ...

  2. poj 3177 Redundant Paths 求最少添加几条边成为双联通图: tarjan O(E)

    /** problem: http://poj.org/problem?id=3177 tarjan blog: https://blog.csdn.net/reverie_mjp/article/d ...

  3. 【解题报告】小白逛公园 vijos

    题目传送门 这道题是一道线段树的一个求一个连续最大字段和是一个区间线段树一个很妙妙的操作,这里后面我们后面就会提到,因为今天博主没有时间了所以先粘一篇代码供大家参考,其实代码理解还是非常的简单的. 代 ...

  4. Mac系统配置php环境

    [写在前面——叨叨叨] -_-#急着配环境的同志们可以绕道.最近学校的实验室里接了一个小项目——考勤刷卡系统,利用RFID在硬件层获取学生卡的ID,通过wifi传输至服务器,进行考勤信息存储,手机端获 ...

  5. php实现redis

    <?php //实例化Redis对象 $red=new Redis(); //链接redis服务 $red->connect('localhost','6379'); //具体操作 $re ...

  6. php 移动或重命名文件(图片)到另一目录下的方法有多种,这里只列出三种:

    php 移动或重命名文件(图片)到另一目录下的方法有多种,这里只列出三种:       方法一:使用copy函数   格式:copy(source,destination)   将文件从 source ...

  7. JQ 封装全选函数

    单击时触发效果: 如果有一个没有选中把全选的勾去了,如果select所有的都选中了,那就把全选勾上 html里: <div class="row cl"> <la ...

  8. 虚拟机服务没有启动的 CentOS 和 Ubuntu 无法上网

    测试用 vmware 安装 OSX,安装补丁时要停止 vmware 的服务.如下图: 结果忘记启动了,导致 centos\ubuntu 等所有虚拟机都无法上网...所有的 启动这四个服务后,一切恢复正 ...

  9. 官方yum源安装选择所需版本mysql数据库并初始化(yum默认安装的是最新版MySQL8.+)

    在官网是找不到5.x系列的域名源的,系统默认是安装的oracle数据库,在安装前需要删除默认的 以下教程来源于官网说明 先去官网下载yum源,地址 https://dev.mysql.com/down ...

  10. Python函数中的参数

    形参:形式参数 实参:实际参数 1.普通参数:严格按照顺序将实参赋值给形参. 2.默认参数:必须放置在参数列表的最后. 3.指定参数:将实参赋值给制定参数. 4.动态参数: *:默认将传入的参数,全部 ...