内容推荐服务提供商 Taboola 如何利用 LoAF 将其发布商合作伙伴网站的 INP 提升高达 36%。

Taboola 如何利用 Long Animation Frames API (LoAF) 并采用智能收益策略,来提升发布商的网站响应能力,同时又不影响广告效果。

David Belford
David Belford

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 的替代品)

总阻塞时间 (TBT) 是一项基于实验室的指标,可确定主线程在什么位置被阻塞的时间过长,足以影响网页响应速度。衡量响应能力的现场指标(例如 INP)可能会受到高 TBT 的影响。Annie Sullivan移动设备上的 TBT 和 INP 之间的相关性进行的调查表明,如果尽可能减少主线程阻塞时间,网站更有可能获得良好的 INP 得分。

这种相关性,再加上 Taboola 的发布商因此,Taboola 将注意力集中在尽可能减少其对该指标的贡献上。

<ph type="x-smartling-placeholder">
</ph> Lighthouse 审核阻塞主线程时间的屏幕截图。主线程总共被多个脚本阻塞 2,630 毫秒,在此期间第三方 JavaScript 贡献了 712 毫秒。Taboola 的 RELEASE.js 脚本负责大部分第三方拦截时间,即 691 毫秒。 <ph type="x-smartling-placeholder">
</ph> 使用 Taboola 的旧引擎时,RELEASE.js 等脚本会阻塞主线程 691 毫秒。

使用 TBT 作为 INP 的替代指标,Taboola 开始监控和优化 JavaScript 执行时间,以限制其对 Core Web Vitals 的潜在影响。他们首先采取了以下措施:

然而,Taboola 注意到,使用这些工具分析 TBT 存在一些局限性:

  • Long Tasks API 无法将任务归因于源网域或特定脚本,这使得识别耗时较长的任务的来源更加困难。
  • Long Tasks API 仅识别耗时较长的任务,而非可能导致渲染延迟的任务和布局更改的组合。

为了应对这些挑战,Taboola 加入了 Long Animation Frames (LoAF) API 源试用,以期更好地了解其对用户输入响应能力的真正影响。通过源试用,用户可以试用新功能或实验性功能,从而能够测试用户可在有限的时间内试用的新兴功能。

必须强调的是,此挑战中最困难的方面是在不影响任何 Google Ads KPI(关键绩效指标)或导致发布商资源延迟的情况下成功改进 INP。

利用 LoAF 评估 INP 的影响

如果渲染更新延迟超过 50 毫秒,就会出现较长的动画帧。通过确定界面更新缓慢的原因(而不是只关注任务耗时较长的原因),Taboola 能够分析该问题对网页响应速度的影响。观察 LoAF 后,Taboola 可以:

  1. 将条目归因于特定 Taboola 任务。
  2. 在部署到生产环境之前,观察特定功能的性能问题。
  3. 通过收集汇总数据来比较 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 创建了以下归因表,该表列出了其可以在哪些方面应用收益机会。

脚本 时长(毫秒)
vpaid/units/33_6_8/infra/cmTagINLINE_INSTREAM.js:106517 997
vpaid/units/33_6_8/infra/cmTagFEED_MANAGER.js:496662 561
vpaid/vPlayer/player/v15.8.6/OvaMediaPlayer.js:44631 336
libtrc/impl.20231212-23-RELEASE.js:821090 857
publisher_name/pmk-20220605.5.js:7728 336
libtrc/card-interference-detector.20231219-7-RELEASE.es6.js:183 239
Taboola RUM 捕获的 LoAF 脚本条目
<ph type="x-smartling-placeholder">

TRECS Engine:新的收益策略

除了使用 LoAF 更好地了解脚本优化机会之外,Taboola 还在重新设计其整个渲染引擎,以尽可能减少 JavaScript 执行和阻塞时间。

TRECS(Taboola 建议可扩展客户端服务)可维护客户端渲染和发布商当前的 JS 代码,同时减少加载 Taboola 推荐内容所需的必需文件的数量和大小。

一旦使用 LoAF 确定了阻塞渲染的任务,“性能衰减器”可以使用 scheduler.postTask() 在让出主线程之前分解这些任务。这种设计可以确保面向用户的关键工作(例如渲染更新)能够尽快执行,而不考虑任何可能占用主线程的现有任务。

以下是“Performance Fader”的 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 和 Performance Fader 的影响,Taboola 进行了一项 A/B 测试,用来衡量 INP 针对现有引擎的效果,并且没有在发布商合作伙伴小组中产生脚本效果。

下表显示了 Taboola 网络中四个匿名发布商的第 75 个百分位的 INP 结果(以毫秒为单位)。

发布方 INP 与 TRECS + 性能衰减器 将 INP 与现有引擎集成 INP 降幅 (%)
发布商 A 48 75 36%
发布商 B 153 163 6%
发布商 C 92 135 33%
发布商 D 37 52 29%

幸运的是,在测试面板上启用 TRECS 和 Performance Fader 之后,广告点击率和每千次展示收入 (RPM) 等业务指标没有受到负面影响。随着 INP 的积极提升,在广告 KPI 方面没有如预期般出现任何负面结果,Taboola 将逐步提升其发布商的以及用户对其产品的看法。

针对前面突出显示的同一客户运行的另一个 Lighthouse 展示了在使用新的引擎时,Taboola 的主线程阻塞时间显著改善。

<ph type="x-smartling-placeholder">
</ph> 屏幕截图:在应用新的 TRECS 和 Performance Fader 引擎以缩短主线程阻塞时间后,Lighthouse 审核阻塞主线程的时间。审计时间缩短至只有 206 毫秒,而优化前的 712 毫秒。 <ph type="x-smartling-placeholder">
</ph> Taboola 的新引擎帮助 RELEASE.js 等脚本将 TBT 缩短了 485 毫秒 (-70%)

这表明,使用 LoAF 确定 INP 的原因并使用 Performance Fader 部署后续收益技术,这让 Taboola 的合作伙伴能够在广告和网页效果方面获得最大的成功。

总结

优化 INP 是一个复杂的过程,尤其是在合作伙伴网站上使用第三方脚本时。在开始进行优化之前,将 INP 归因到特定脚本可避免任何猜测,并避免对其他网站性能指标的潜在损害。事实证明,LoAF API 是识别和解决 INP 问题的重要工具,尤其是对嵌入的第三方 INP 问题,因为 LoAF API 可以让它们精确定位其具体 SDK 改进机会,同时消除网页上存在的其他技术的干扰。

当与良好的收益策略(例如使用 scheduler.postTask())结合使用时,LoAF 可以帮助您观察和了解网页响应不佳的原因,而这反过来又为您提供了改进网站 INP 所需的信息。

特别感谢 Google 的 Gilberto Cocchi、Noam Rosenthal 和 Rick Viscomi,以及 Taboola 工程和产品团队的 Dedi Hakak、Anat Dagan 和 Omri Ariav 为这项工作做出的贡献。