时间:2022-9-14 作者:悬浮的青春 分类: javascript
### 1\. 什么是懒加载
懒加载也叫做延迟加载、按需加载,指的是在长网页中延迟加载图片数据,是一种较好的网页性能优化的方式。
在比较长的网页或应用中,如果图片很多,所有的图片都被加载出来,而用户只能看到可视窗口的那一部分图片数据,这样就浪费了性能。
如果我们使用图片的懒加载就可以解决以上问题。在滚动屏幕之前,可视化区域之外的图片不会进行加载,在滚动屏幕时才加载。这样使得网页的加载速度更快,减少了服务器的负载。懒加载适用于图片较多,页面较长的页面场景中。
**懒加载与预加载的区别:**
这两种方式都是提高网页性能的方式,两者主要区别是一个是提前加载,一个是迟缓甚至不加载。懒加载对服务器前端有一定的缓解压力作用,预加载则会增加服务器前端压力。
* **懒加载**也叫延迟加载,指的是在长网页中延迟加载图片的时机,当用户需要访问时,再去加载,这样可以提高网站的首屏加载速度,提升用户的体验,并且可以减少服务器的压力。它适用于图片很多,页面很长的电商网站的场景。懒加载的实现原理是,将页面上的图片的 src 属性设置为空字符串,将图片的真实路径保存在一个自定义属性中,当页面滚动的时候,进行判断,如果图片进入页面可视区域内,则从自定义属性中取出真实路径赋值给图片的 src 属性,以此来实现图片的延迟加载。
* **预加载**指的是将所需的资源提前请求加载到本地,这样后面在需要用到时就直接从缓存取资源。通过预加载能够减少用户的等待时间,提高用户的体验。我了解的预加载的最常用的方式是使用 js 中的 image 对象,通过为 image 对象来设置 scr 属性,来实现图片的预加载。
**使用懒加载的好处:**
* **减少无用资源的加载**:使用懒加载明显减少了服务器的压力和流量,同时也减小了浏览器的负担。
* **提升用户体验**: 如果同时加载较多图片,可能需要等待的时间较长,这样影响了用户体验,而使用懒加载就能大大的提高用户体验。
* **防止加载过多图片而影响其他资源文件的加载** :会影响网站应用的正常使用。
### 2\. 图片懒加载的基本实现
图片的加载是由`src`引起的,当对`src`赋值时,浏览器就会请求图片资源。根据这个原理,我们使用HTML5 的`data-xxx`属性来储存图片的路径,在需要加载图片的时候,将`data-xxx`中图片的路径赋值给`src`,这样就实现了图片的按需加载,即懒加载。
注意:`data-xxx` 中的`xxx`可以自定义,这里我们使用`data-src`来定义。
懒加载的实现重点在于确定用户需要加载哪张图片,在浏览器中,可视区域内的资源就是用户需要的资源。所以当图片出现在可视区域时,获取图片的真实地址并赋值给图片即可。
使用原生JavaScript实现懒加载:
**知识点:**
(1)`window.innerHeight` 是浏览器可视区的高度
(2)`document.body.scrollTop || document.documentElement.scrollTop` 是浏览器滚动的过的距离
(3)`imgs.offsetTop` 是元素顶部距离文档顶部的高度(包括滚动条的距离)
(4)图片加载条件:`img.offsetTop < window.innerHeight + document.body.scrollTop;`
**代码实现:**
```javascript
<div class="container">
<img src="loading.gif" data-src="pic.png">
<img src="loading.gif" data-src="pic.png">
<img src="loading.gif" data-src="pic.png">
<img src="loading.gif" data-src="pic.png">
<img src="loading.gif" data-src="pic.png">
<img src="loading.gif" data-src="pic.png">
</div>
<script>
var imgs = document.querySelectorAll('img');
function lozyLoad(){
var scrollTop = document.body.scrollTop || document.documentElement.scrollTop;
var winHeight= window.innerHeight;
for(var i=0;i < imgs.length;i++){
if(imgs[i].offsetTop < scrollTop + winHeight ){
imgs[i].src = imgs[i].getAttribute('data-src');
}
}
}
window.onscroll = lozyLoad();
</script>
```
### 3\. 结合节流优化图片懒加载
上面的图片进行懒加载的时候,需要不断监听的scroll事件,然后判断图片是否已经在首屏页面当中,如果已经在首屏就进行加载,如果没有则无需进行拉取。我们知道scroll这类事件会被频繁触发,对性能的影响非常大,所以才有了防抖和节流。那么针对这个scroll事件,我们完全可以使用节流函数包一下,让它隔一段时间再去触发,避免多余性能消耗,如下:
```javascript
const imgLazyLoad = throttle(() => console.log('懒加载操作'), 1000)
document.addEventListener('scroll', imgLazyLoad)
```
用封装好的throttle去包装好懒加载操作,这样用户在频繁滚动滚动条的时候就不会产生因为频繁触发而带来的性能问题,这也是节流非常典型的一个应用。
### 4\. Intersection Observer实现图片懒加载
Intersection Observer是HTML5新增的API,可以用来实现图片懒加载。MDN中对Intersection Observer的解释:
> `**IntersectionObserver**`**接口** (从属于[Intersection Observer API](https://developer.mozilla.org/en-US/docs/Web/API/Intersection_Observer_API)) 提供了一种异步观察目标元素与其祖先元素或顶级文档视窗([viewport](https://developer.mozilla.org/zh-CN/docs/Glossary/Viewport))交叉状态的方法。祖先元素与视窗([viewport](https://developer.mozilla.org/zh-CN/docs/Glossary/Viewport))被称为**根(root)。**
> 当一个`IntersectionObserver`对象被创建时,其被配置为监听根中一段给定比例的可见区域。一旦IntersectionObserver被创建,则无法更改其配置,所以一个给定的观察者对象只能用来监听可见区域的特定变化值;然而,你可以在同一个观察者对象中配置监听多个目标元素。
上面使用节流来解决了scroll频繁触发的问题,这也说明之前的图片懒加载方案是存在一定问题的;而Intersection Observer不需要监听scroll事件,可以做到只要图片元素出现在可视区域内,就能进行回调,具体如下:
```javascript
document.addEventListener("DOMContentLoaded", function() {
var lazyImages = [].slice.call(document.querySelectorAll("img.lazy"));
if ("IntersectionObserver" in window) {
let lazyImageObserver = new IntersectionObserver(function(entries, observer) {
entries.forEach(function(entry) {
if (entry.isIntersecting) {
let lazyImage = entry.target;
lazyImage.src = lazyImage.dataset.src;
lazyImage.srcset = lazyImage.dataset.srcset;
lazyImage.classList.remove("lazy");
lazyImageObserver.unobserve(lazyImage);
}
});
});
lazyImages.forEach(function(lazyImage) {
lazyImageObserver.observe(lazyImage);
});
}
});
```
上面就是使用Intersection Observer完成图片懒加载的方法,该方法唯一的缺点就是兼容性还不是很好,如果需要兼容版本较低的浏览器,则要根据浏览器的版本封装更通用的方法。
### 5\. 延迟加载视频
图片和视频这类静态资源资源占比都最大。与图片一样,视频同样可以延迟加载,来达到优化性能的目的。正常情况下加载视频,使用的是`<video>`标签,那么对于一些需要由用户自己播放的视频,最好指定`<video>`标签的preload属性为none,这样浏览器就不会预加载任何视频数据。为了占用空间,使用poster属性为`<video>`占位。如下:
```javascript
<video controls preload="none" poster="replace.jpg">
<source src="main.webm" type="video/webm">
<source src="main.mp4" type="video/mp4">
</video>
```
### 6\. 使用第三方延迟加载库
除了上面介绍的一些延迟加载方法之外,还可以借助一些已经封装好的第三方库,下面是一些成熟的第三方库:
* [lozad.js](https://github.com/ApoorvSaxena/lozad.js) 是超轻量级且只使用 Intersection Observer 的库, 因此它的性能极佳,但如果要在旧版本浏览器上使用,则需要配置polyfill。
* [lazysizes](https://github.com/aFarkas/lazysizes) 是功能全面的延迟加载库,其使用的模式与本文所示的代码示例非常相似,会自动与 `<img>` 元素上的`lazyload` 类绑定,然后在`data-src` 和/或 `data-srcset` 属性中指定图像网址,该库还可以通过许多插件进行扩展,执行延迟各种资源等操作。
* 如果使用React,可以使用 [react-lazyload](https://github.com/jasonslyvia/react-lazyload)来进行图片懒加载操作,这个库是React图片懒加载的主流解决方案。
标签: 网页