图片懒加载的原理和实现

一,前置知识 1,为什么要图片懒加载 【图片懒加载的原理和实现】懒加载是一种对网页性能优化的方式,比如当访问一个页面的时候,优先显示可视区域的图片而不是一次性加载所有图片,当需要显示时,再发送图片请求,避免打开网页时加载过多资源。
当一个网站的加载图片过多时就需要懒加载的协助,页面图片多时,在首次载入时一次性加载会耗费时间长,使用懒加载可以使页面加载速度快、减轻服务器的压力、节省流量。
如下图:

随着滚轮滚动,底部的图片会被不断地加载,从而显示在页面上,也就是说懒加载其实就是按需加载,当页面需要显示图片的时候才进行加载,否则不加载。
那问题来了,直接发起http请求,下载所有图片,然后存储在本地,再进行页面渲染不行吗???
这里就要讲图片的特殊性了,常规情况下,我们图片是这样写的:

图片懒加载的原理和实现
文章图片

它用的是src来链接外部资源,用来替换这个位置。它是可以无视跨域的(基于这一点,才有了jsonp的跨域实现)。
也就是说,它不是页面加载时发起http请求获取页面数据时直接得到的图片,而是先得到:
图片懒加载的原理和实现
文章图片

也就是说只是得到这么一个记录图片位置的字符串,然后把数据赋值给:
图片懒加载的原理和实现
文章图片

然后让image的src来发起请求,获取对应的图片放置到DOM树的这个位置上,从而实现图片的页面渲染!
于是就可以知道,当进入页面的时候,其实我们已经把所有的图片的这个地址信息拿到了,图片懒加载的作用就是让这个图片的src按需发起请求,获取图片。
同样是这个界面,当我滚动滚轮时,看network的请求情况:

随着滚轮的滚动,不断地发起请求来获取图片。
接着查看这个瀑布图:
图片懒加载的原理和实现
文章图片

可以看到每次只加载2张图片(这是因为我页面每行只有2张图片,按照它懒加载的算法,每次都是两张图片同时进入屏幕,所以才同时获取两张图片),这样就把请求错开了。
但是如果不用图片懒加载的话,就会是这个样子的:
图片懒加载的原理和实现
文章图片

因为浏览器可以并行加载图片(不超过10个并行任务好像……额,是好像),所以就好多图片一起加载了 ,这还只是8张图片,那如果是大量的图片呢?那不就是把主线程大量占用了嘛!
所以我们需要使用图片的懒加载技术来优化页面,最大的目的就是让主线程空闲变多,页面加载更快。
2,实现图片懒加载的原理 看到这里,我们已经明白了图片加载是src属性做的事情,那么我们只要不给这个src属性赋值不就不会发起请求了嘛!!
然后,html5还提供自定义属性的方式:data-xxx
我们可以先把图片地址存在这里面,然后判断这个图片是否进入屏幕了,一旦进入屏幕,就把这个图片地址赋值给src,让它发起请求获取图片不就好了!
图片懒加载的原理和实现
文章图片
图片懒加载的原理和实现
文章图片
图片懒加载的原理和实现
文章图片
图片懒加载的原理和实现
文章图片
图片懒加载的原理和实现
文章图片
图片懒加载的原理和实现
文章图片
图片懒加载的原理和实现
文章图片
图片懒加载的原理和实现
文章图片

图片懒加载的原理和实现
文章图片

但是实际上,我们的网络也没有那么稳定,如果网络不佳,图片将会是这样的:
图片懒加载的原理和实现
文章图片

这将会造成页面布局的混乱,为了避免这种情况,前端的小伙伴们第一时间肯定是想到占位。那通过啥占位?通常是一张loading的gif动图,这样可以给用户带来更好的体验,但是新的问题又出现了!占位的图片它既然也是通过src取得的,那它占那么多位置,不也需要发起请求嘛???
实际上,浏览器已经很聪明了,当页面的有多张重复图片使用时,它只会发起一次http请求,后续就直接使用了,不会再发请求,也就是说,使用占位图片,只是额外增加一个图片请求罢了。。大气如本少年,肯定是允许的呀!!
3,实现判断图片是否在屏幕上 最基础的,主要是需要使用到这两个方法:
1,DOMobj.getBoundingClientRect().top//获取该元素到屏幕顶部的距离 2,window.innerHeight//屏幕的高度

也就是当元素到屏幕顶部的距离小于屏幕高度时,就可以判定图片进入了屏幕。就把图片地址赋值给src,从而发起请求获取图片。
图片懒加载的原理和实现
文章图片

二,原生实现图片的懒加载 基于上面说的方法,写的原生实现代码:
- 锐客网 ="text/css"> .lazy-load{ display: block; width: 90%; margin: 0 auto; }
图片懒加载的原理和实现
文章图片
图片懒加载的原理和实现
文章图片
图片懒加载的原理和实现
文章图片
图片懒加载的原理和实现
文章图片
图片懒加载的原理和实现
文章图片
图片懒加载的原理和实现
文章图片
图片懒加载的原理和实现
文章图片
图片懒加载的原理和实现
文章图片
="text/javascript"> //图片加载的函数 function imgonload() { //把伪数组转化为真数组 let imgs = [...document.querySelectorAll('.lazy-load')] for(let i=0; i图片懒加载的原理和实现
文章图片
图片懒加载的原理和实现
文章图片
图片懒加载的原理和实现
文章图片
图片懒加载的原理和实现
文章图片
图片懒加载的原理和实现
文章图片
图片懒加载的原理和实现
文章图片
图片懒加载的原理和实现
文章图片
图片懒加载的原理和实现
文章图片
="text/javascript"> //图片加载的函数 function imgonload() { //把伪数组转化为真数组 let imgs = [...document.querySelectorAll('.lazy-load')] for(let i=0; i图片懒加载的原理和实现
文章图片

三,使用:Intersection Observer API Intersection Observer API提供了一种异步检测目标元素与祖先元素或 viewport 相交情况变化的方法。
过去,要检测一个元素是否可见或者两个元素是否相交并不容易,很多解决办法不可靠或性能很差。然而,随着互联网的发展,这种需求却与日俱增,比如,下面这些情况都需要用到相交检测:
1,图片懒加载——当图片滚动到可见时才进行加载 2,内容无限滚动——也就是用户滚动到接近内容底部时直接加载更多,而无需用户操作翻页,给用户一种网页可以无限滚动的错觉 3,检测广告的曝光情况——为了计算广告收益,需要知道广告元素的曝光情况 4,在用户看见某个区域时执行任务或播放动画 5,过去,相交检测通常要用到事件监听,并且需要频繁调用Element.getBoundingClientRect()方法以获取相关元素的边界信息。事件监听和调用Element.getBoundingClientRect()都是在主线程上运行,因此频繁触发、调用可能会造成性能问题。这种检测方法极其怪异且不优雅。

- 锐客网 ="text/css"> .lazy-load{ display: block; width: 90%; margin: 0 auto; }
图片懒加载的原理和实现
文章图片
图片懒加载的原理和实现
文章图片
图片懒加载的原理和实现
文章图片
图片懒加载的原理和实现
文章图片
图片懒加载的原理和实现
文章图片
图片懒加载的原理和实现
文章图片
图片懒加载的原理和实现
文章图片
图片懒加载的原理和实现
文章图片
="text/javascript"> document.addEventListener("DOMContentLoaded", function() { let lazyImages = [...document.querySelectorAll('.lazy-load')]; if ("IntersectionObserver" in window) { // 创建一个观察函数,以便待会调用 let lazyImageObserver = new IntersectionObserver(function(entries, observer) { entries.forEach(function(entry) { if (entry.isIntersecting) { let lazyImage = entry.target; lazyImage.src = https://www.it610.com/article/lazyImage.dataset.src; // 替换 src URL lazyImageObserver.unobserve(lazyImage); // 解除观察 } }); }); // 对所有需要懒加载的图片进行 “暗中观察” lazyImages.forEach(function(lazyImage) { lazyImageObserver.observe(lazyImage); }); }else{ alert('您的浏览器不支持 IntersectionObserver'); } });

    推荐阅读