如何利用 Long Animation Frames API (LoAF) 和采用智能广告投放策略,让 Taboola 在不影响广告效果的情况下提升发布商网站的响应速度。
Interaction to Next Paint (INP) 是一项指标,用于评估网站对用户输入的响应速度。INP 衡量的是从用户开始互动(例如点击、轻触或输入)到获得视觉反馈所用的时间。INP 将于 2024 年 3 月取代 First Input Delay (FID) 成为 Core Web Vitals 指标。
Taboola 是全球领先的内容发现平台,可在开放网络上每秒提供 50 万条推荐内容。借助这些建议,Taboola 的 9,000 家独家发布商合作伙伴可以通过广告创收并吸引观众。发布商使用 JavaScript 在其网页上呈现推荐内容。
由于第三方 JavaScript 可能会影响网页对用户输入的快速响应能力,因此 Taboola 投入了大量资源来缩减 JavaScript 文件大小和执行时间。Taboola 一直在重新设计其整个渲染引擎,并直接使用浏览器 API(而非抽象化 API),以最大限度地减少对 INP 的影响。
本案例研究介绍了 Taboola 如何使用新的 Long Animation Frames (LoAF) API 衡量其对网页响应速度的影响,进而采取具体优化措施来改善用户体验,从而提升 INP。
将 TBT 用作 INP 的代理
Total Blocking Time (TBT) 是一个实验室指标,用于确定主线程处于屏蔽状态的时间是否足够长,以致可能影响页面响应能力。用于衡量响应速度的字段指标(例如 INP)可能会受到 TBT 较高的影响。Annie Sullivan 对移动设备上的 TBT 与 INP 之间的相关性进行了调查,结果表明,当主线程阻塞时间最短时,网站更有可能获得良好的 INP 得分。
鉴于这种相关性,以及 Taboola 发布商对 TBT 偏高问题的担忧,Tabola 将其工作重点放在尽量减少对此指标的影响上。
![有关主线程阻塞时间的 Lighthouse 审核的屏幕截图。主线程总共被多个脚本阻塞了 2,630 毫秒,其中第三方 JavaScript 占用了 712 毫秒。Taboola 的 RELEASE.js 脚本占据了大部分第三方阻塞时间(691 毫秒)。](https://web.dev/static/case-studies/taboola-inp/image/fig-1.png?hl=zh-cn)
RELEASE.js
等脚本会阻塞主线程 691 毫秒。
将 TBT 用作 INP 的代理指标后,Taboola 开始监控和优化 JavaScript 执行时间,以限制其对 Core Web Vitals 的潜在影响。他们首先执行了以下操作:
- 使用 Long Tasks API 识别和优化现场存在问题的脚本。
- 使用 PageSpeed Insights API 每天评估 1 万到 1.5 万个网址,从而估算 TBT 的贡献。
不过,Taboola 发现,使用这些工具分析 TBT 存在一些限制:
- Long Tasks API 无法将任务归因于源网域或特定脚本,因此更难以识别长任务的来源。
- Long Tasks API 仅会识别长任务,而不是可能导致渲染延迟的任务和布局更改组合。
为了应对这些挑战,Taboola 加入了长动画帧 (LoAF) API 源代码试用计划,以便更好地了解该 API 对用户输入响应能力的实际影响。源试用可让您使用新功能或实验性功能,让开发者测试新兴功能,并让用户在有限的时间内试用这些功能。
需要特别指出的是,这项挑战最难的部分在于,如何在不影响任何广告 KPI(关键绩效指标)或导致发布商资源延迟的情况下,成功提升 INP。
使用 LoAF 评估 INP 影响
如果渲染更新延迟超过 50 毫秒,就会出现长动画帧。通过找出界面更新缓慢的原因(而不仅仅是任务耗时长),Tablola 能够在实际环境中分析其对网页响应速度的影响。通过观察 LoAF,Taboola 能够:
- 将条目归因于特定的 Taboola 任务。
- 在将特定功能部署到生产环境之前,观察其性能问题。
- 收集汇总数据,以便在 A/B 测试中比较不同的代码版本,并生成有关关键成功指标的报告。
以下 JavaScript 是生产环境中用于收集 LoAF 的简化版本,以便隔离 Taboola 的影响。
function loafEntryAnalysis (entry) {
if (entry.blockingDuration === 0) {
return;
}
let taboolaIsMajor = false;
const hasInteraction = entry.firstUIEventTimestamp > 0;
let taboolaDuration = 0;
const nonTaboolaLoafReport = {};
const taboolaLoafReport = {};
entry.scripts.forEach((script) => {
const taboolaScriptBlockingDuration = handleLongAnimationFrameScript(script, taboolaLoafReport, nonTaboolaLoafReport);
taboolaDuration += taboolaScriptBlockingDuration;
if (taboolaScriptBlockingDuration > 0 || taboolaDuration > entry.duration / 2) {
taboolaIsMajor = true;
}
});
generateToboolaLoafReport(taboolaLoafReport, nonTaboolaLoafReport, hasInteraction, taboolaIsMajor);
if (hasInteraction) {
const global = _longAnimationFramesReport.global;
global.inpBlockingDuration = Math.max(global.inpBlockingDuration, entry.blockingDuration);
if (taboolaIsMajor) {
global.taboolaInpBlockingDuration = Math.max(global.taboolaInpBlockingDuration, entry.blockingDuration);
}
}
}
const observer = new PerformanceObserver(list => {
for (const entry of list.getEntries()) {
loafEntryAnalysis(entry);
}
});
observer.observe({ type: 'long-animation-frame', buffered: true });
- 通过使用
loafEntryAnalysis
函数,Taboola 能够找出自己是主要贡献者的条目。 - 如果脚本总时长的一半以上是由 Taboola 导致的,或者 Taboola 脚本的运行时间超过 50 毫秒,则 Taboola 会被视为主要影响因素。
- 如果用户互动因动画帧过长而延迟,系统会生成
firstUIEventTimeStamp
。最长的屏蔽时长将被视为总体 INP 得分。我们还可以确定 Taboola 何时触发了firstUIEventTimeStamp
,以便计算 Taboola INP 得分。
通过 LoAF 收集的数据帮助 Taboola 创建了以下归因表,该表确定了可以应用富有成效的机会的领域。
TRECS Engine:新的让出策略
除了使用 LoAF 来更好地了解脚本优化机会之外,Taboola 还一直在重新设计其整个渲染引擎,以大幅缩短 JavaScript 执行和阻塞时间。
TRECS(Taboola 推荐可扩展客户端服务)可维护客户端呈现和发布商的当前 JS 代码,同时减少加载 Taboola 推荐内容所需的强制性文件数量和大小。
使用 LoAF 识别出渲染阻塞任务后,“性能淡出”功能会在使用 scheduler.postTask()
让出主线程之前拆分这些任务。这种设计可确保无论主线程是否可能占用任何现有任务,都可以尽快执行面向用户的重要工作(例如渲染更新)。
以下是“效果淡出”任务运行程序的 JS 代码段:
/**
* Send a task to run using the Fader. The task will run using the browser Scheduler, by the configuration settings, or immediately.
* @param task
* @param isBlocker
*/
function sendTaskToFader (task, isBlocker = true) {
const publisherFaderChoice = fillOptimizationGlobals(); // Loading publisher choice
const applyYielding = publisherFaderChoice === OptimizationFaderType.Responsiveness;
if (applyYielding) {
return runAsPostTask(task, isBlocker);
}
return runImmediately(task);
}
/**
* Yielding method using scheduler.postTask and falling back to setTimeout when it's not availabe based on the publisher choice
*/
function runAsPostTask (task, isBlocker = true) {
if ('scheduler' in window && 'postTask' in scheduler) {
const priority = isBlocker ? 'user-blocking': 'background';
return window?.scheduler?.postTask(task, { priority });
}
const publisherChoiceEnableFallback = fillPublisherChoices();
if (publisherChoiceEnableFallback) {
return new Promise(resolve => {
window.setTimeout(() => {
resolve(task());
}, 0);
});
}
return runImmediately(task);
}
sendTaskToFader
函数
- 使用
runAsPostTask
,后者会在后台使用scheduler.postTask()
(如果该 API 可用),或回退到setTimeout
。 - 此函数会封装导致动画帧和 INP 较长的代码部分中的函数调用。它会将这些代码段拆分为更短的任务,从而减少 INP。
业务指标
得益于 LoAF,Taboola 能够更好地了解 LoAF 对 INP 的影响。该工具还突出显示了可用于新 TRECS 引擎的脚本优化机会。
为了确定 TRECS 和效果衰减器的影响,Taboola 在发布商合作伙伴的样本组中开展了一项 A/B 测试,衡量了 INP 与不使用脚本的现有引擎相比的效果。
下表显示了 Taboola 广告联盟中四个匿名发布商的 INP 结果(以毫秒为单位,75 百分位数)。
幸运的是,在测试面板上启用 TRECS 和效果淡出功能后,广告点击率和每千次展示收入 (RPM) 等业务指标并未受到不利影响。随着 INP 的这种积极改善,广告 KPI 没有出现任何负面结果,这符合预期,Taboola 将逐步改善发布商对其产品的看法。
在之前提到的同一客户上运行的另一次 Lighthouse 测试结果表明,使用新引擎后,Taboola 的主线程阻塞时间显著缩短。
![应用新的 TRECS 和性能淡出引擎以缩短主线程阻塞时间后,Lighthouse 审核主线程阻塞时间的屏幕截图。审核时间缩短至仅 206 毫秒,而优化前为 712 毫秒。](https://web.dev/static/case-studies/taboola-inp/image/fig-2.png?hl=zh-cn)
RELEASE.js
等脚本将 TBT 缩短了 485 毫秒(-70%)。
这表明,使用 LoAF 来确定 INP 的原因,并通过效果衰减器部署后续的让位技术,可让 Taboola 的合作伙伴最大限度提升广告和网页效果。
总结
优化 INP 是一个复杂的过程,尤其是在合作伙伴网站上使用第三方脚本时。在开始优化之前,将 INP 归因于特定脚本可消除所有猜测,并避免对其他网站性能指标造成潜在损害。LoAF API 已被证明是一款有价值的工具,可帮助您发现和解决 INP 问题,尤其是对于嵌入的第三方,它可以帮助他们找出特定的 SDK 改进机会,同时消除来自网页上其他技术的干扰。
与良好的让出策略(例如使用 scheduler.postTask()
)搭配使用时,LoAF 可帮助您观察和了解网页响应缓慢的原因,从而为您提供改善网站 INP 所需的信息。
特别感谢 Google 的 Gilberto Cocchi、Noam Rosenthal 和 Rick Viscomi,以及 Taboola 工程和产品团队的 Dedi Hakak、Anat Dagan 和 Omri Ariav 对本研究做出的贡献。