众所周知,性能优化一般就两个东西,不加载,和缓存
当然不加载是不行的,所以今天就来讲讲延迟加载
当前网页除了大规模 js 加载,还有一些我们可以进行优化的地方
对于字体文件加载,可以看我的文章 - 字体模块设计
图片加载#
图片性能优化包含很多内容,包括压缩,格式,用视频替换 GIF, 根据尺寸提供图片,使用 webp, 使用 cdn.
这些不是我们今天的内容,今天来看看图片延迟加载
最新的浏览器默认实现浏览器级别的延迟加载,可以使用 loading 属性来开启
<img loading="lazy" />
我们还可以通过 IntersectionObserver 对象,来开启对 img 的延迟加载更精细的控制,例如在视口中出现 1s 以上才开始显示图片
// 获取所有需要延迟加载的图片元素
const lazyImages = document.querySelectorAll(".lazy-loaded-image");
// 设置 IntersectionObserver 的选项
const options = {
root: null,
rootMargin: "0px",
threshold: 0.5
};
// 创建 IntersectionObserver 对象
const lazyImageObserver = new IntersectionObserver((entries, observer) => {
entries.forEach((entry) => {
if (entry.isIntersecting && entry.intersectionRatio >= 0.5) {
// 如果图片在视口中出现1s以上,开始加载图片
setTimeout(() => {
const lazyImage = entry.target;
lazyImage.src = lazyImage.dataset.src;
lazyImage.classList.remove("lazy");
lazyImageObserver.unobserve(lazyImage);
}, 1000);
}
});
}, options);
// 观察所有需要延迟加载的图片元素
lazyImages.forEach((lazyImage) => {
lazyImageObserver.observe(lazyImage);
});
css 文件中的图片#
css 文件中的图片不可以用上面的加载方式,但是我们同样可以使用视口监视的方式,来动态添加类名已达到延迟加载图片的目的
.lazy-background { background-image: url("hero-placeholder.jpg");
/* Placeholder image */}
.lazy-background.visible { background-image: url("hero.jpg");
/* The final image */}
我们通过修改上面的代码将 setTimeout 中的内容替换为 (其他代码相对应的改动)
lazyBackGround.classList.add("visible");
来达到动态改变 css 加载的图片方式实现延迟加载
视频的延迟加载#
video 没有 lazy 属性,但是有个 preload 可以使用
<video controls preload="none" poster="one-does-not-simply-placeholder.jpg"> <source src="one-does-not-simply.webm" type="video/webm"> <source src="one-does-not-simply.mp4" type="video/mp4"></video>
这里有个 poster 属性,这个属性非常有用,可以将图片当作占位图来使用
前文提到过,我们可以使用视频来替换 GIF 显示,这是因为相同内容,视频相对于 GIF 有明显的体积优势
这种场景下,我们的 video 标签是这样的
这是一个延迟加载的 自动播放,一直循环的视频
<video class="lazy" autoplay muted loop playsinline width="610" height="254" poster="one-does-not-simply.jpg"> <source data-src="one-does-not-simply.webm" type="video/webm"> <source data-src="one-does-not-simply.mp4" type="video/mp4"></video>
我们依然可以使用 IntersectionObserver 来动态的替换 source 元素的 src , 来精细的控制延迟加载
if (video.isIntersecting) {
for (var source in video.target.children) {
var videoSource = video.target.children[source];
if (
typeof videoSource.tagName === 'string' &&
videoSource.tagName === 'SOURCE'
) {
videoSource.src = videoSource.dataset.src;
}
}
video.target.load();
video.target.classList.remove('lazy');
lazyVideoObserver.unobserve(video.target);
}
iframe 的延迟加载#
iframe 同样支持 loading=lazy, 最简单的方法就是直接添加到标签上,这对于页面中嵌入大量视频的场景非常有效