前言
在上次我们聊到前端性能优化之图片懒加载,虽然对性能有了一定的优化,但是还是有些地方可以再优化。那么今天我们再继续思考思考,哪里可以再优化的地方。
懒加载
懒加载技术是比较简单且容易理解的,我们先来回顾一下。
在页面需要加载大量图片的情况下,我们可以给每个img标签的src属性赋予一个默认加载的图片地址。由于src属性的特殊性,这是必填的并且浏览器会提前去下载src的图片。
如果我们把原来要展示的图片都直接给src的话,这会导致页面可能一下子无法把全部的图片显示出来。所以,我们让真正的图片地址赋给一个自定义data- 属性,等需要加载该图片的时候,就把data- 属性赋值给src,这样减轻了浏览器的压力。
目前,已经减轻了浏览器的压力,但是我们是通过判断滚动页面图片是否进入可视区来加载图片的。稍微细心点我们就能发现,轻轻滚动页面就会触发好几遍判断事件。我们再把节流方法加入这个优化方案里面,这样就已经达到了最佳。
/**
* @param {Function} fn - 需要节流的函数
* @param {number} wait - 时间间隔(毫秒)
* @returns {Function} - 返回一个节流后的函数
*/
// 节流函数
function throttle(fn, wait) {
let lastTime = 0
return function (...args) {
const now=Date.now()
if (now - lastTime >= wait) {
lastTime = now
fn.apply(this.args)
}
}
}
好了,我们基本已经出色的完成了懒加载的功能。我们回顾一下是如何实现的。我们通过不断使用getBoundingClientRect()来判断是否进入了可视区。但是,getBoundingClientRect()会不断获取元素所在位置,即不断的触发回流重绘。这也也影响了我们的性能,我们要减少回流和重绘,所以就有了更优秀的方法。
Intersection Observer
Intersection Observer这是浏览器的API,用于异步观察目标元素与其祖先元素或视口交叉的状态。我们无需手动监听滚动事件,浏览器原生支持观察原生是否进入视口,此方法性能更好,代码也更简洁。
基本用法
const observer=new Intersection Observer(callback,options)
- callback:每当被观察的元素的可见性发生变化时,调用回调函数。
- entries:被观察元素的列表,每个元素都是一个IntersectionObserverEntry对象
- observer:IntersectionObserver实例本身
- options:一个可选参数对象,用来配置观察器的行为
- root:用于观察的祖先元素,默认为视口
- rootMargin:根元素的外边距,用于扩大或缩小根元素的判断区域
- threshold:规定在什么可见比例下触发回调的数组
Callback
const callback=(entries,observer)=>{
entries.forEach(entry=>{
if(entry.isIntersecting){
// 元素进入可视区,加载图片
const img=entry.target
img.src=img.dataset.src
// 停止观察该元素
observer.unobserve(entry.targer)
}
})
}
Options
const options={
root:null, // 默认视口
rootMargin:'0px', // 设置外边距
threshold:0.1 // 设置可见比例(0~1)的数组
}
完整实现
document.addEventListener('DOMContentLoaded', () => {
const imgs = document.querySelectorAll('img[data-src]')
const callback = (entries, observer) => {
entries.forEach(entry => {
if (entry.isIntersecting) {
const img = entry.target
img.src = img.dataset.src
observer.unobserve(img)
}
})
}
const options = {
root: null,
rootMargin: '0px',
threshold: 0.1
}
const observer = new IntersectionObserver(callback, options)
imgs.forEach(img => {
observer.observe(img)
})
})
Ending
以上就图片懒加载的优化升级版了,目前IntersectionObserver是现代浏览器的主流方法,性能比较优异。