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

如何利用 Long Animation Frames API (LoAF) 和采用智能广告投放策略,让 Taboola 在不影响广告效果的情况下提升发布商网站的响应速度。

David Belford
David Belford

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 毫秒)。
使用 Taboola 的旧版引擎时,RELEASE.js 等脚本会阻塞主线程 691 毫秒。

将 TBT 用作 INP 的代理指标后,Taboola 开始监控和优化 JavaScript 执行时间,以限制其对 Core Web Vitals 的潜在影响。他们首先执行了以下操作:

不过,Taboola 发现,使用这些工具分析 TBT 存在一些限制:

  • Long Tasks API 无法将任务归因于源网域或特定脚本,因此更难以识别长任务的来源。
  • Long Tasks API 仅会识别长任务,而不是可能导致渲染延迟的任务和布局更改组合。

为了应对这些挑战,Taboola 加入了长动画帧 (LoAF) API 源代码试用计划,以便更好地了解该 API 对用户输入响应能力的实际影响。源试用可让您使用新功能或实验性功能,让开发者测试新兴功能,并让用户在有限的时间内试用这些功能。

需要特别指出的是,这项挑战最难的部分在于,如何在不影响任何广告 KPI(关键绩效指标)或导致发布商资源延迟的情况下,成功提升 INP。

使用 LoAF 评估 INP 影响

如果渲染更新延迟超过 50 毫秒,就会出现长动画帧。通过找出界面更新缓慢的原因(而不仅仅是任务耗时长),Tablola 能够在实际环境中分析其对网页响应速度的影响。通过观察 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 脚本条目

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 + 效果淡化器的 INP 将 INP 与现有引擎搭配使用 INP 下降幅度 (%)
发布商 A 48 75 36%
发布商 B 153 163 6%
发布商 C 92 135 33%
发布商 D 37 52 29%

幸运的是,在测试面板上启用 TRECS 和效果淡出功能后,广告点击率和每千次展示收入 (RPM) 等业务指标并未受到不利影响。随着 INP 的这种积极改善,广告 KPI 没有出现任何负面结果,这符合预期,Taboola 将逐步改善发布商对其产品的看法。

在之前提到的同一客户上运行的另一次 Lighthouse 测试结果表明,使用新引擎后,Taboola 的主线程阻塞时间显著缩短。

应用新的 TRECS 和性能淡出引擎以缩短主线程阻塞时间后,Lighthouse 审核主线程阻塞时间的屏幕截图。审核时间缩短至仅 206 毫秒,而优化前为 712 毫秒。
Taboola 的新引擎帮助 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 对本研究做出的贡献。