预提取如何帮助 Terra 将广告点击率提高 30% 并加快 Largest Contentful Paint。

预提取资源可加快网页加载速度并提升业务指标。

Guilherme Moser de Souza
Guilherme Moser de Souza

预提取是一种技术,用于通过下载近期可能需要的资源(甚至整个网页)来加快网页加载速度。研究表明,加载时间越短,转化率就越高,用户体验也会更好。

Terra 是巴西最大的内容门户之一,提供娱乐、新闻和体育内容,每月有超过 6,300 万的唯一访问者。我们与 Terra 的工程团队合作,在其网站的某些部分使用预加载技术,缩短了文章的加载时间。

本案例介绍了 Terra 的转化历程实施情况,该实施使其移动设备上的广告点击率 (CTR) 提高了 11%,桌面设备上的广告点击率提高了 30%,Largest Contentful Paint (LCP) 时间缩短了 50%。

预提取策略

预提取功能已经存在一段时间了,但请务必谨慎使用,因为它会为不立即必要的资源消耗额外的带宽。应谨慎使用此技术,以免使用不必要的数据流量。对于 Terra,如果满足以下条件,系统会预提取文章:

  • 指向预提取文章的链接的可见性:Terra 使用 Intersection Observer API 检测包含要预提取的文章的部分的可见性。
  • 有利于增加数据使用量的条件:如前所述,预加载是一种会消耗额外数据的推测性性能改进,在某些情况下,这可能不是理想的结果。为了降低浪费带宽的可能性,Terra 会使用 Network Information APIDevice Memory API 来确定是否提取下一篇文章。Terra 仅在以下情况下提取下一篇文章:
    • 连接速度至少为 3G,且设备至少有 4GB 的内存,
    • 或设备搭载 iOS。
  • CPU 空闲:最后,Terra 会使用 requestIdleCallback 检查 CPU 是否处于空闲状态且能够执行额外工作,该函数会在主线程空闲时或在特定(可选)截止期限到达时(以先到者为准)处理回调。

遵循这些条件可确保 Terra 仅在必要时提取数据,从而节省带宽和电池电量,并最大限度地减少最终未使用的预提取的影响。

满足上述条件后,Terra 会预加载下方以蓝色突出显示的“相关内容”和“为你推荐”部分中显示的文章。

Terra 网站上预提取了链接的两个部分的屏幕截图。左侧突出显示的是“相关内容”部分,右侧突出显示的是“为你推荐”部分。

业务影响

为了衡量此技术的影响,Terra 首先在文章页面的“相关内容”部分推出了此功能。借助 UTM 代码,他们能够区分预提取的文章和未预提取的文章,以便进行比较。经过两周的成功 A/B 测试,Terra 决定在“为你推荐”部分中添加预加载功能。

预提取文章后,广告指标总体有所提高,而 LCP 和首字节时间 (TTFB) 缩短了:

指标 移动设备 桌面设备
广告点击率 +11% +30%
广告可见度 +10.5% +6%
LCP -51% -73%
TTFB -83% -84%

如果谨慎使用预提取功能,可以显著缩短网页加载时间、提升广告指标并缩短 LCP 时间。

技术详情

您可以通过使用 rel=prefetchrel=preload 等资源提示、通过 quicklinkGuess.js 等库,或使用较新的 Speculation Rules API 来实现预提取。Terra 选择通过以下方式实现此功能:使用提取 API(优先级为)与 Intersection Observer 实例结合使用。Terra 之所以做出这一选择,是因为它支持 Safari,而 Safari 尚不支持 rel=prefetch 或 Speculation Rules API 等其他预加载方法,而且 Terra 的需求并不需要功能齐全的 JavaScript 库。

以下 JavaScript 大致相当于 Terra 使用的代码:

function prefetch(nodeLists) {
  // Exclude slow ECTs < 3g
  if (navigator.connection &&
    (navigator.connection.effectiveType === 'slow-2g'
      || navigator.connection.effectiveType === '2g')
  ) {
    return;
  }

  // Exclude low end device which is device with memory <= 2GB
  if (navigator.deviceMemory && navigator.deviceMemory <= 2) {
    return;
  }

  const fetchLinkList = {};

  const observer = new IntersectionObserver(function (entries) {
    entries.forEach(function (entry) {
      if (entry.isIntersecting) {
        if (!fetchLinkList[entry.target.href]) {
          fetchLinkList[entry.target.href] = true;

          fetch(entry.target, {
            priority: 'low'
          });
        }

        observer.unobserve(entry = entry.target);
      }
    });
  });
}

const idleCallback = window.requestIdleCallback || function (cb) {
  let start = Date.now();

  return setTimeout(function () {
    cb({
      didTimeout: false,
      timeRemaining: function () {
        return Math.max(0, 50 - (Date.now() - start));
      }
    });
  }, 1);
}

idleCallback(function () {
  prefetch(nodeLists)
})
  • prefetch 函数会先检查连接质量和设备内存是否达到最低要求,然后再发起预加载。
  • 然后,它使用 IntersectionObserver 监控元素何时在视口中变为可见,并随后将网址添加到列表中以进行预加载。
  • 预加载进程由 requestIdleCallback 调度,目的是在主线程空闲时执行 prefetch 函数。

总结

谨慎使用预加载功能可以显著缩短未来导航请求的加载时间,从而减少用户体验过程中的摩擦并提高互动度。预加载会导致加载可能不会使用的额外字节,因此 Terra 采取了额外的措施,以便仅在网络状况良好且能够获取此信息的设备上进行预加载。

特别感谢 Terra 工程团队的 Gilberto Cocchi、Harry Theodoulou、Miguel Carlos Martínez Díaz、Barry Pollard、Jeremy Wagner、Leonardo Bellini 和 Lucca Paradeda 对本工作的贡献。