Taboola 如何利用 Long Animation Frames API (LoAF) 并采用智能让步策略,在不影响广告效果的情况下提高发布商网站的响应速度。
Interaction to Next Paint (INP) 是一种评估网站对用户输入响应速度的指标。INP 衡量从用户开始交互(例如单击、轻触或键入)到产生视觉反馈之间的时间。INP 将于 2024 年 3 月取代 First Input Delay (FID) 成为 Core Web Vital。
Taboola 是世界领先的内容发现平台,每秒在开放网络上支持 500,000 次推荐。这些推荐使 Taboola 的 9,000 家独家发布商合作伙伴能够通过其受众群体获利和互动。发布商使用 Javascript 在其页面上呈现推荐。
由于第三方 JavaScript 可能会影响页面快速响应用户输入的能力,因此 Taboola 一直大力投入减少其 JavaScript 文件大小和执行时间。Taboola 一直在重新设计其整个渲染引擎,并直接使用浏览器 API 而不进行抽象,以最大限度地减少其对 INP 的影响。
本案例研究涵盖了 Taboola 通过使用新的 Long Animation Frames (LoAF) API 来衡量其对现场页面响应速度的影响,以及随后为应用特定优化以改善用户体验所做的努力,从而改进 INP 的历程。
TBT 作为 INP 的代理
Total Blocking Time (TBT) 是一种基于实验室的指标,用于识别主线程阻塞时间过长,可能影响页面响应速度的位置。衡量响应速度的现场指标(例如 INP)可能会受到高 TBT 的影响。 Annie Sullivan 对 移动设备上 TBT 和 INP 之间相关性的调查表明,当主线程阻塞时间最小化时,网站更有可能获得良好的 INP 分数。
这种相关性,加上 Taboola 发布商对高 TBT 的担忧,促使 Taboola 将注意力集中在最大限度地减少其对该指标的贡献上。

RELEASE.js
这样的脚本会阻塞主线程 691 毫秒。Taboola 使用 TBT 作为 INP 的代理指标,开始监控和优化 JavaScript 执行时间,以限制其对 Core Web Vitals 的潜在影响。他们首先执行以下操作
- 使用 Long Tasks API 识别和优化现场有问题的脚本。
- 通过使用 PageSpeed Insights API 评估每天 10,000 到 15,000 个 URL 来估算 TBT 贡献。
但是,Taboola 注意到使用这些工具分析 TBT 存在一些限制
- Long Tasks API 无法将任务归因于来源域或特定脚本,因此更难识别长任务的来源。
- Long Tasks API 仅识别 长任务,而不是可能导致渲染延迟的任务和布局更改的组合。
为了应对这些挑战,Taboola 加入了 Long Animation Frames (LoAF) API 来源试用,以更好地了解其对用户输入响应速度的实际影响。 来源试用允许访问新的或实验性功能,使开发人员能够测试新兴功能,供其用户在限定时间内试用。
必须强调的是,此挑战中最困难的方面是在成功改进 INP 的同时,不影响任何广告 KPI(关键绩效指标)或导致发布商的资源延迟。
使用 LoAF 评估 INP 影响
当渲染更新延迟超过 50 毫秒时,会发生长动画帧。通过识别用户界面更新缓慢的原因(而不仅仅是长任务),Taboola 能够分析其对 现场页面响应速度的影响。通过观察 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 引擎:新的让步策略
除了使用 LoAF 更好地了解脚本优化机会外,Taboola 一直在重新设计其整个渲染引擎,以显着减少 Javascript 执行和阻塞时间。
TRECS(Taboola Recommendations Extensible Client Service,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 能够更好地了解其对 INP 的影响。该工具还突出了可以用作新 TRECS 引擎一部分的脚本优化机会。
为了确定 TRECS 和性能衰减器的影响,Taboola 对一组发布商合作伙伴进行了 A/B 测试,在没有脚本让步的情况下,针对现有引擎测量 INP。
下表显示了 Taboola 网络中四家匿名发布商的第 75 个百分位数的 INP 结果(以毫秒为单位)。
幸运的是,当在测试面板上启用 TRECS 和性能衰减器时,广告点击率和每千次展示收入 (RPM) 等业务指标没有受到负面影响。凭借 INP 的这种积极改进,并且如预期那样,广告 KPI 没有出现任何负面结果,Taboola 将逐步提高其发布商对其产品的认知度。
对同一客户进行的另一次 Lighthouse 运行(之前已突出显示)表明,在使用新引擎时,Taboola 的主线程阻塞时间得到了显着改善。

RELEASE.js
这样的脚本将 TBT 减少了 485 毫秒(-70%)。这表明,使用 LoAF 识别 INP 的原因并部署随后的性能衰减器让步技术,使 Taboola 的合作伙伴能够在广告和页面性能方面取得最大成功。
结论
优化 INP 是一个复杂的过程,尤其是在合作伙伴网站上使用第三方脚本时。在开始优化之前,将 INP 归因于特定脚本可以消除任何猜测,并避免对其他网站性能指标造成潜在损害。LoAF API 已被证明是识别和解决 INP 问题的宝贵工具,特别是对于嵌入的 3P,因为它允许他们查明其特定的 SDK 改进机会,同时消除页面上存在的其他技术的干扰。
当与良好的 让步策略(例如使用 scheduler.postTask()
)结合使用时,LoAF 可以帮助您观察和了解页面响应速度差的原因,从而为您提供改进网站 INP 所需的信息。
特别感谢来自 Google 的 Gilberto Cocchi、Noam Rosenthal 和 Rick Viscomi,以及来自 Taboola 工程和产品团队的 Dedi Hakak、Anat Dagan 和 Omri Ariav 对这项工作的贡献。