前端性能优化之图片懒加载实战与原理解析

104 阅读2分钟

什么是图片懒加载?

图片懒加载(Lazy Load)是一种前端性能优化技术,指的是页面图片并不是在页面初始加载时全部请求,而是只在图片即将进入可视区域时才进行加载。这样可以有效减少首屏加载压力,提升页面打开速度,优化用户体验。

如下demo(转自西维)往下滚动页面时,原本不可见的图片逐渐进入可视区域。

为什么要用懒加载?

  • 提升首屏加载速度:页面图片过多时,全部加载会极大拖慢首屏渲染,影响用户体验。
  • 节省带宽资源:用户未浏览到的图片不会被加载,节省流量。
  • 减轻服务器压力:减少并发请求数量,降低服务器负载。

懒加载的常见的两种实现方式

1. 滚动事件+getBoundingClientRect

原理:监听页面滚动事件,遍历所有待加载图片,判断其是否进入可视区域(通过getBoundingClientRect),如果进入则替换src为真实图片地址。

滚动监听懒加载流程

基于滚动事件的懒加载流程

核心代码示例:

const viewHeight = document.documentElement.clientHeight;
const eles = document.querySelectorAll("img[data-original][lazyload]");
const lazyload = function () {
  Array.prototype.forEach.call(eles, function (item) {
    if (item.dataset.original === "") return;
    rect = item.getBoundingClientRect();
    if (rect.bottom >= 0 && rect.top < viewHeight) {
      var img = new Image();
      img.src = item.dataset.original;
      img.onload = function () {
        item.src = item.dataset.original;
        item.removeAttribute("data-original");
        item.removeAttribute("lazyload");
      };
    }
  });
};
window.addEventListener("scroll", lazyload);
document.addEventListener("DOMContentLoaded", lazyload);

虽然这种实现方式的兼容性好,原理简单,但缺点就是滚动事件触发频繁,需配合防抖/节流优化;每次都要遍历所有图片,性能有一定损耗。

因为scroll是每一个像素点触发一次,在我们滚动时,就会触发超级频繁,如用事件监听并在控制台输出触发次数:

image.png

2. IntersectionObserver

原理:利用浏览器原生的IntersectionObserver接口,异步监听图片是否进入可视区域,进入时再加载图片。

IntersectionObserver懒加载流程

基于 IntersectionObserver 的懒加载流程

核心代码示例:

const eles = document.querySelectorAll("img[data-original][lazyload]");
const observer = new IntersectionObserver(function (changes) {
  changes.forEach(function (element) {
    if (element.intersectionRatio > 0 && element.intersectionRatio <= 1) {
      const img = new Image();
      img.src = element.target.dataset.original;
      img.onload = function () {
        element.target.src = img.src;
      };
    }
  });
});
eles.forEach((item) => {
  observer.observe(item);
});

IntersectionObserver相比于scroll就无需手动监听滚动事件,性能更优,代码更简洁,只有部分老旧浏览器(如IE)不支持(可用 polyfill 兼容)。

总结

图片懒加载是前端性能优化的重要手段,能有效提升页面加载速度和用户体验。推荐优先使用 IntersectionObserver 实现,兼容性要求高时可退而求其次用滚动监听+getBoundingClientRect 方式。