预提取资源可加快网页加载速度并提升业务指标。
预提取是一种技术,用于通过下载近期可能需要的资源(甚至整个网页)来加快网页加载速度。研究表明,加载时间越短,转化率就越高,用户体验也会更好。
Terra 是巴西最大的内容门户之一,提供娱乐、新闻和体育内容,每月有超过 6,300 万的唯一访问者。我们与 Terra 的工程团队合作,在其网站的某些部分使用预加载技术,缩短了文章的加载时间。
本案例介绍了 Terra 的转化历程实施情况,结果是移动设备上的广告点击率 (CTR) 提高了 11%,桌面设备上的广告点击率提高了 30%,Largest Contentful Paint (LCP) 时间缩短了 50%。
预提取策略
预提取功能已经存在一段时间了,但请务必谨慎使用,因为它会为不立即必要的资源消耗额外的带宽。应谨慎使用此技术,以免使用不必要的数据流量。对于 Terra,如果满足以下条件,系统会预提取文章:
- 指向预提取文章的链接的可见性:Terra 使用 Intersection Observer API 检测包含要预提取的文章的部分的可见性。
- 有利于增加数据使用量的条件:如前所述,预加载是一种会消耗额外数据的推测性性能改进,在某些情况下,这可能不是理想的结果。为了降低浪费带宽的可能性,Terra 会使用 Network Information API 和 Device Memory API 来确定是否提取下一篇文章。Terra 仅在以下情况下提取下一篇文章:
- 连接速度至少为 3G,且设备至少有 4GB 的内存,
- 或设备搭载 iOS。
- CPU 空闲:最后,Terra 会使用
requestIdleCallback
检查 CPU 是否处于空闲状态且能够执行额外的工作,该方法会在主线程空闲时或在特定(可选)截止期限(以先到者为准)处理回调。
遵循这些条件可确保 Terra 仅在必要时提取数据,从而节省带宽和电池电量,并最大限度地减少最终未使用的预提取的影响。
满足上述条件后,Terra 会预加载下方以蓝色突出显示的“相关内容”和“为你推荐”部分中显示的文章。
业务影响
为了衡量此技术的影响,Terra 首先在文章页面的“相关内容”部分推出了此功能。借助 UTM 代码,他们能够区分预提取的文章和未预提取的文章,以便进行比较。经过两周的成功 A/B 测试,Terra 决定在“为你推荐”部分中添加预加载功能。
预加载文章后,广告指标总体有所提高,而 LCP 和首字节时间 (TTFB) 缩短了:
如果谨慎使用预提取功能,可以显著缩短网页加载时间、提升广告指标并缩短 LCP 时间。
技术详情
您可以通过使用 rel=prefetch
或 rel=preload
等资源提示、通过 quicklink 或 Guess.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 对本工作的贡献。