如何利用 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 将其工作重点放在尽量减少对此指标的影响上。
将 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 的主线程阻塞时间显著缩短。
这表明,使用 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 对本研究做出的贡献。