Skip to content
On this page

万物皆可懒加载

前言

最好的代码,就是没有代码。

同样的,体验最好的网页,就是没有内容的网页。

这段话乍一听似乎脱离实际,没有内容的网页根本没有加载的必要。

但静下来分析,却道出了前端体验优化的核心:精简页面内容

再多优化,都比不上从根源上精简页面的内容,减少加载的资源。

所以,此节内容为大家讲述:

前端工程精简加载资源体积和资源数量的解决方案:懒加载各类资源

资源懒加载一般应用于需要加载外部资源的元素,例如 <img>, <video>, <iframe>, <picture> 等。

当懒加载目标元素在视口(ViewPort)外时,不加载对应资源。目标元素接近或进入视口时,才触发加载资源。

从而减少页面加载资源的数量,精简加载资源体积,优化用户体验。


作者个人简介:Ned同学的个人说明书

大纲(学完则删):

三类资源懒加载实现方案

1、监听滚动事件方案

第一种实现方案是通过监听浏览器页面滚动事件(scroll),动态计算视口内元素位置,从而判断懒加载目标元素,触发资源加载。

以图片元素懒加载为例,我们需要监听页面滚动事件,并计算出每张图片与视口顶部的相对距离。

如果图片在视口内,就加载该图片,否则就不加载。

html
<img data-lazyload data-src="/isNed.jpg" />
js
// 1. 获取所有需要懒加载的图片元素
const lazyloadImages = document.querySelectorAll('[data-lazyload]');

// 2. 监听页面滚动事件
window.addEventListener('scroll', () => {
  lazyloadImages.forEach(img => {
    if (img.getAttribute('data-loaded')) {
      return;
    }
    // 3.  获取图片与视口顶部的相对距离
    const topPos = img.getBoundingClientRect().top;
    // 4. 与 视口高度(window.innerHeight)对比,判断是否在视口内
    if (topPos < window.innerHeight) {
      // 5. 如果图片在当前视口内,就加载该图片
      img.src = img.getAttribute('data-src');
      img.setAttribute('data-loaded', true)
    }
  });
});

在上述代码中,我们首先获取所有需要懒加载的图片元素,通过 querySelectorAll 获取带有指定的懒加载标记属性 data-lazyload 的元素引用,这些图片初始化时没有设置src值,而真正的懒加载目标图片URL则保存在 data-src 属性中,这样就能实现初始化时暂不加载图片,由代码逻辑控制图片何时加载。

然后,我们监听页面滚动事件 window.addEventListener('scroll'),在滚动事件的回调中,遍历所有需要懒加载的图片元素 lazyloadImages.forEach。

对于每个图片元素,我们首先检查其 data-loaded 属性是否为 true,如果是,则说明该图片已经加载过了,我们就跳过该元素。

否则,我们通过 getBoundingClientRect() 方法获取该图片距离视口(viewport)顶部的位置,并通过和当前视口高度(window.innerHeight)对比,判断该图片当前是否在视口内,即图片与视口顶部的距离,是否小于当前视口的高度。

最后,如果图片在视口内,就将该图片的 src 属性设置为 data-src 属性的值,从而触发图片资源加载,并将 data-loaded 属性设置为 true,表示该图片已经加载过了。

这样我们就实现了对图片类资源的懒加载,初始化时暂不加载图片资源,减少加载资源数量和体积,提高初始化时渲染性能,当图片进入浏览器视口时,再真正触发加载。

实际应用时,我们应该对这一方案做更多细节上的优化,如:

  • 设置图片默认的宽高,以避免懒加载完成后,页面高度变化,被判断为意外布局变化,影响 CLS 评分。
  • 添加图片未加载占位符和加载中动画,改善用户等待加载时的视觉和体验。
  • 计算位置、判断目标元素是否出现在视口时,还要考虑水平方向上的页面滚动位置,计算 getBoundingClientRect() 返回的 top, bottom, left, right 4个方向相对视口位置。
  • 对 scroll 事件添加节流优化,降低触发回调函数的频率,避免影响页面渲染的FPS。
  • 依赖 scroll 事件,容易对页面渲染性能产生负面影响,这也是监听滚动事件方案的主要痛点。

过低的 scroll 事件回调触发频率,会导致懒加载触发不灵敏。

而过高的 scroll 事件回调触发频率,又会因为大量计算,导致JS执行耗时太长,阻塞UI绘制,产生页面卡顿。

Released under the MIT License.