预提取资源可缩短网页加载时间并提升业务指标。
预提取是一项技术,用于通过下载近期可能会需要的资源(甚至整个网页)来加快网页加载速度。研究表明,加载时间越短,转化率越高,用户体验就越好。
Terra 是巴西最大的内容门户之一,提供娱乐、新闻和体育内容,每月的唯一身份访问者数量超过 6300 万。我们与 Terra 的工程团队合作,在其网站的特定版块上使用预提取技术,从而缩短报道的加载时间。
本案例研究介绍了 Terra 实施历程后,移动设备上的广告点击率 (CTR) 提高了 11%,桌面广告点击率 (CTR) 提高了 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 选择将低优先级 fetch API 与 Intersection Observer 实例结合使用,以达到此目的。Terra 之所以做出这一选择,是因为它支持 Safari,但 Safari 尚不支持 rel=prefetch
或 Speculation Rules API 等其他预提取方法,而且功能齐全的 JavaScript 库也能满足 Terra 的需求。
以下 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 对这项工作所做的贡献。