Long Animation Frames API

Long Animation Frames API(LoAF,发音为 Lo-Af)是对 Long Tasks API 的更新,旨在更好地了解界面 (UI) 更新缓慢的问题。这对于识别可能影响衡量响应速度的 Interaction to Next Paint (INP) Core Web Vital 指标的缓慢动画帧,或识别影响流畅度的其他界面卡顿非常有用。

API 的状态

浏览器支持

  • Chrome:123。
  • Edge:123。
  • Firefox:不受支持。
  • Safari:不受支持。

来源

从 Chrome 116 到 Chrome 122 进行源试用后,LoAF API 已从 Chrome 123 开始提供

背景知识:Long Tasks API

浏览器支持

  • Chrome:58.
  • Edge:79。
  • Firefox:不受支持。
  • Safari:不受支持。

来源

Long Animation Frames API 是 Long Tasks API 的替代方案,Long Tasks API 已在 Chrome 中推出一段时间了(自 Chrome 58 起)。顾名思义,借助 Long Task API,您可以监控长任务,即占用主线程 50 毫秒或更长时间的任务。您可以使用 PerformanceLongTaskTiming 界面和 PeformanceObserver 监控长时间运行的任务:

const observer = new PerformanceObserver((list) => {
  console.log(list.getEntries());
});

observer.observe({ type: 'longtask', buffered: true });

长任务可能会导致响应速度问题。如果用户尝试与网页互动(例如点击按钮或打开菜单),但主线程正在处理耗时任务,则用户的互动会延迟,直到该任务完成。

为了提高响应速度,通常建议拆分耗时较长的任务。如果将每项长任务拆分为一系列较小的任务,则可以在这些任务之间执行更重要的任务,以避免在响应互动时出现明显延迟。

因此,在尝试提高响应速度时,通常首先要做的是运行性能轨迹并查看长时间运行的任务。您可以通过实验室审核工具(例如 Lighthouse,其中包含避免出现长时间运行的主线程任务审核)或在 Chrome 开发者工具中查看长时间运行的任务来进行检查。

在确定响应速度问题时,实验室测试通常不是好的起点,因为这些工具可能不包含互动,即使包含,也只是可能互动的一部分。理想情况下,您应衡量现场互动缓慢的原因。

Long Tasks API 的缺点

使用性能观察器衡量现场执行的长时间任务只有部分用处。实际上,除了发生了耗时任务以及耗时长短之外,它不会提供太多信息。

实时用户监控 (RUM) 工具通常会使用此方法来分析长任务的数量或时长趋势,或确定长任务发生在哪些网页上,但如果没有导致长任务的根本原因的详细信息,此方法的用途就很有限。Long Tasks API 仅提供基本归因模型,该模型充其量只能告诉您发生长任务的容器(顶级文档或 <iframe>),但无法告诉您调用该容器的脚本或函数,如下面的典型条目所示:

{
  "name": "unknown",
  "entryType": "longtask",
  "startTime": 31.799999997019768,
  "duration": 136,
  "attribution": [
    {
      "name": "unknown",
      "entryType": "taskattribution",
      "startTime": 0,
      "duration": 0,
      "containerType": "window",
      "containerSrc": "",
      "containerId": "",
      "containerName": ""
    }
  ]
}

Long Tasks API 也是一个不完整的视图,因为它可能也会排除一些重要任务。某些更新(例如渲染)会在单独的任务中进行,理想情况下,应将导致该更新的先前执行操作包含在内,以准确衡量该互动的“总工作量”。如需详细了解依赖于任务的限制,请参阅说明文档的“长任务的不足之处”部分

最后一个问题是,衡量长任务时,系统只会报告耗时超过 50 毫秒的各个任务。动画帧可以由多个小于 50 毫秒限制的任务组成,但这些任务总体上仍会阻止浏览器渲染。

Long Animation Frames API

浏览器支持

  • Chrome:123。
  • Edge:123。
  • Firefox:不受支持。
  • Safari:不受支持。

来源

Long Animation Frames API (LoAF) 是一个新 API,旨在解决 Long Tasks API 的一些缺点,让开发者能够获得更实用的分析洞见,以帮助解决响应速度问题并提高 INP,还能深入了解流畅度问题。

良好的响应能力意味着网页能够快速响应与其进行的互动。这涉及能够及时绘制用户需要的任何更新,并避免阻止这些更新的发生。对于 INP,建议在 200 毫秒内响应,但对于其他更新(例如动画),即使 200 毫秒也可能过长。

Long Animation Frames API 是衡量阻塞工作量的替代方法。顾名思义,Long Animation Frames API 用于衡量长动画帧,而不是衡量各个任务。动画帧时长过长是指渲染更新延迟超过 50 毫秒(与 Long Tasks API 的阈值相同)。

动画帧时长是从需要进行渲染的任务开始时计算的。如果潜在长动画帧中的第一个任务不需要渲染,则在非渲染任务完成后,长动画帧会结束,并在下一个任务开始时启动新的潜在长动画帧。当超过 50 毫秒(renderStart 时间为 0)时,此类非渲染长动画帧仍会包含在 Long Animation Frames API 中,以便衡量可能阻塞的工作。

您可以通过与包含 PerformanceObserver 的长任务类似的方式观察长动画帧,但要查看 long-animation-frame 类型:

const observer = new PerformanceObserver((list) => {
  console.log(list.getEntries());
});

observer.observe({ type: 'long-animation-frame', buffered: true });

您还可以从性能时间轴查询之前的长动画帧,如下所示:

const loafs = performance.getEntriesByType('long-animation-frame');

不过,性能条目有 maxBufferSize,之后系统会丢弃较新的条目,因此建议使用 PerformanceObserver 方法。long-animation-frame 缓冲区大小设置为 200,与 long-tasks 相同。

查看帧而非任务的好处

从帧的角度(而不是任务的角度)来看这一点的主要优势在于,一个长动画可以由任意数量的任务组成,这些任务累积起来会产生一个长动画帧。这解决了前面提到的最后一点,即 Long Tasks API 可能不会显示动画帧之前许多较小的渲染阻塞任务的总和。

这种针对长任务的替代视图的另一个优势是,能够提供整个帧的时间细分。与 Long Tasks API 不同,LoAF 不仅包含 startTimeduration,还包含有关帧时长的各个部分的更详细的细分。

帧时间戳和时长

  • startTime:长动画帧相对于导航开始时间的开始时间。
  • duration:长动画帧的时长(不包括呈现时间)。
  • renderStart:渲染周期的开始时间,包括 requestAnimationFrame 回调、样式和布局计算、大小调整观察器和交叉观察器回调。
  • styleAndLayoutStart:样式和布局计算所用时间段的开始时间。
  • firstUIEventTimestamp:在此帧期间要处理的第一个界面事件(鼠标/键盘等)的时间。
  • blockingDuration:动画帧会阻塞输入或其他高优先级任务的处理时长(以毫秒为单位)。

blockingDuration 说明

一个长动画帧可能由多个任务组成。blockingDuration 是超过 50 毫秒的任务时长的总和(包括最长任务的最终呈现时长)。

例如,如果一个长动画帧由两个任务组成,分别为 55 毫秒和 65 毫秒,后跟一个 20 毫秒的渲染,则 duration 大约为 140 毫秒,blockingDuration 为 (55 - 50) + (65 + 20 - 50) = 40 毫秒。在 140 毫秒长的动画帧期间,其中 40 毫秒被视为处理输入的阻塞时间。

是查看 duration 还是 blockingDuration

对于常见的 60 赫兹显示屏,浏览器会尝试至少每 16.66 毫秒调度一个帧(以确保流畅更新),或在输入处理等高优先级任务之后调度一个帧(以确保快速响应更新)。不过,如果没有输入,也没有其他高优先级任务,但有其他任务队列,则浏览器通常会在当前帧结束后很长时间(远远超过 16.66 毫秒)继续执行其他任务,无论这些任务在其中的分解程度如何。也就是说,浏览器始终会尝试优先处理输入,但可能会选择处理任务队列,而不是渲染更新。这是因为渲染是一项成本高昂的过程,因此为多项任务处理组合渲染任务通常会导致总体工作量减少。

因此,blockingDuration 较低或为零的长动画帧应该仍然能对输入做出响应。因此,通过拆分长任务来减少或消除 blockingDuration 是提高 INP 衡量下的响应能力的关键。

不过,无论 blockingDuration 如何,大量的长动画帧都表示界面更新延迟,因此仍会影响流畅度,并导致滚动或动画的界面感觉迟缓,即使这些问题在 INP 衡量的响应速度方面不太严重也是如此。如需了解此方面的问题,请查看 duration,但这些问题在优化方面可能更棘手,因为您无法通过拆分工作来解决此问题,而必须减少工作量。

帧时间

借助前面提到的时间戳,可以将长动画帧划分为以下时间点:

计时 计算
开始时间 startTime
结束时间 startTime + duration
工作时长 renderStart ? renderStart - startTime : duration
渲染时长 renderStart ? (startTime + duration) - renderStart: 0
渲染:布局前时长 styleAndLayoutStart ? styleAndLayoutStart - renderStart : 0
渲染:样式和布局时长 styleAndLayoutStart ? (startTime + duration) - styleAndLayoutStart : 0

改进脚本归因

long-animation-frame 条目类型包含导致动画帧延迟时间较长(对于超过 5 毫秒的脚本)的每个脚本的更准确归因数据。

与 Long Tasks API 类似,此信息将以归因条目数组的形式提供,其中每个条目都详细说明了:

  • nameEntryType 都会返回 script
  • 一个有意义的 invoker,用于指明脚本的调用方式(例如 'IMG#id.onload''Window.requestAnimationFrame''Response.json.then')。
  • 脚本入口点的 invokerType
    • user-callback:从 Web 平台 API 注册的已知回调(例如 setTimeoutrequestAnimationFrame)。
    • event-listener:平台事件(例如 clickloadkeyup)的监听器。
    • resolve-promise:平台 Promise 的处理脚本(例如 fetch()。请注意,对于 Promise,同一 Promise 的所有处理脚本都会混合在一起作为一个“脚本”.
    • reject-promise:与 resolve-promise 相同,但用于拒绝。
    • classic-script:脚本评估(例如 <script>import()
    • module-script:与 classic-script 相同,但适用于模块脚本。
  • 该脚本的单独时间数据:
    • startTime:调用条目函数的时间。
    • duration:从 startTime 到后续微任务队列完成处理之间的时长。
    • executionStart:编译后的时间。
    • forcedStyleAndLayoutDuration:在此函数内处理强制布局和样式的总时间(请参阅过载)。
    • pauseDuration:在“暂停”同步操作(提醒、同步 XHR)中花费的总时间。
  • 脚本来源详情:
    • sourceURL:脚本资源名称(如果有,否则为空)。
    • sourceFunctionName:脚本函数名称(如果有,否则为空)。
    • sourceCharPosition:脚本字符位置(如果可用,否则为 -1)。
  • windowAttribution:出现长动画帧的容器(顶级文档或 <iframe>)。
  • window:对同源窗口的引用。

通过源代码条目(如果提供),开发者可以准确了解长动画帧中的每个脚本的调用方式,包括调用脚本中的字符位置。这会显示导致动画帧延迟的 JavaScript 资源中的确切位置。

long-animation-frame 性能条目示例

包含单个脚本的完整 long-animation-frame 效果条目示例如下:

{
  "blockingDuration": 0,
  "duration": 60,
  "entryType": "long-animation-frame",
  "firstUIEventTimestamp": 11801.099999999627,
  "name": "long-animation-frame",
  "renderStart": 11858.800000000745,
  "scripts": [
    {
      "duration": 45,
      "entryType": "script",
      "executionStart": 11803.199999999255,
      "forcedStyleAndLayoutDuration": 0,
      "invoker": "DOMWindow.onclick",
      "invokerType": "event-listener",
      "name": "script",
      "pauseDuration": 0,
      "sourceURL": "https://web.dev/js/index-ffde4443.js",
      "sourceFunctionName": "myClickHandler",
      "sourceCharPosition": 17796,
      "startTime": 11803.199999999255,
      "window": [Window object],
      "windowAttribution": "self"
    }
  ],
  "startTime": 11802.400000000373,
  "styleAndLayoutStart": 11858.800000000745
}

可以看出,这会提供前所未有的大量数据,让网站能够了解渲染更新缓慢的原因。

在该字段中使用 Long Animation Frames API

虽然 Chrome 开发者工具和 Lighthouse 等工具有助于发现和重现问题,但它们是实验室工具,可能会忽略只有现场数据才能提供的用户体验重要方面。

Long Animation Frames API 旨在用于现场收集用户互动的重要情境数据,而 Long Tasks API 无法做到这一点。这有助于您发现和重现您可能无法通过其他方式发现的交互性问题。

支持检测长动画帧的功能 API

您可以使用以下代码来测试是否支持该 API:

if (PerformanceObserver.supportedEntryTypes.includes('long-animation-frame')) {
  // Monitor LoAFs
}

Long Animation Frames API 最明显的用例是帮助诊断和解决互动到下次绘制 (INP) 问题,这也是 Chrome 团队开发此 API 的主要原因之一。良好的 INP 是指从互动到绘制帧,所有互动都应在 200 毫秒内响应。由于 Long Animation Frames API 会衡量用时至少为 50 毫秒的所有帧,因此大多数存在问题的 INP 都应包含 LoAF 数据,以帮助您诊断这些互动。

“INP LoAF”是指包含 INP 互动的 LoAF,如以下图所示:

网页上长动画帧的示例,其中突出显示了 INP LoAF。
网页可能包含多个 LoAF,其中一个与 INP 互动相关。

在某些情况下,INP 事件可能会跨越两个 LoAF,通常是指在帧开始渲染前一帧的部分后发生互动,因此事件处理脚本会在下一帧中处理:

网页上长动画帧的示例,其中突出显示了 INP LoAF。
网页可能包含多个 LoAF,其中一个与 INP 互动相关。

在极少数情况下,它甚至可能跨越两个 LoAF。

通过记录与 INP 互动相关联的 LoAF 数据,您可以获取有关 INP 互动的更多信息,以便对其进行诊断。这对于了解输入延迟特别有用,因为您可以查看该帧中运行的其他脚本。

如果您的事件处理程序无法重现所见的处理时长呈现延迟值,了解原因也非常有用,因为系统可能会为您的用户运行其他脚本,而这些脚本可能未包含在您自己的测试中。

没有直接的 API 可将 INP 条目与其相关的 LoAF 条目或条目相关联,但可以通过比较各个条目的开始时间和结束时间在代码中执行此操作(请参阅 WhyNp 示例脚本)。web-vitals包含 v4 中 INP 归因接口的 longAnimationFramesEntries 属性中的所有相交 LoAF。

关联 LoAF 条目后,您可以添加带有 INP 归因的信息。scripts 对象包含一些最有价值的信息,因为它可以显示这些帧中运行的其他内容,因此将这些数据信标回传到您的分析服务后,您可以更深入地了解互动速度缓慢的原因。

报告 INP 互动中的 LoAF 是查找网页上最紧迫的互动问题的好方法。每位用户与您的网页的互动方式可能有所不同,如果 INP 归因数据量足够大,INP 归因数据中就会包含一些潜在问题。这样,您就可以按脚本量对脚本进行排序,以了解哪些脚本与 INP 速度缓慢相关。

将更多长动画数据报告回分析端点

仅查看 INP LoAF 的一个缺点是,您可能会错过其他可能导致未来 INP 问题的潜在改进领域。这可能会导致您陷入一种追逐尾巴的感觉:您解决一个 INP 问题,希望能取得巨大的改进,但发现下一个最慢的互动速度只比它快了一点,因此 INP 没有太大改善。

因此,您不应仅查看 INP LoAF,而应考虑网页生命周期内的所有 LoAF:

网页包含许多 LoAF,其中一些 LoAF 发生在互动期间(即使不是 INP 互动)。
查看所有 LoAF 有助于发现未来的 INP 问题。

不过,每个 LoAF 条目都包含大量数据,因此您可能希望仅将分析范围限定为部分 LoAF。此外,由于长动画帧条目可能非常大,因此开发者应决定应将条目中哪些数据发送到分析服务。例如,条目的摘要时间和脚本名称,或者可能被视为必要的其他一些最少量情境数据。

以下是减少长动画帧数据量的一些建议模式:

哪种模式最适合您,取决于您在优化方面的进度,以及长动画帧的普遍程度。对于从未针对响应速度进行过优化的网站,可能存在许多 LoAF,因此您可能需要仅限于查看有互动的 LoAF,或者设置较高的阈值,或者仅查看最差的 LoAF。

在解决常见的响应速度问题后,您可以扩大范围,不局限于互动或长时间阻塞,也可以降低阈值。

观察包含互动的长动画帧

如需获得有关 INP 长动画帧以外的深入分析,您可以查看 blockingDuration 较高且包含互动(可通过 firstUIEventTimestamp 值的存在检测到)的所有 LoAF。

这也是一种更简单的监控 INP LoAF 的方法,而不是尝试建立这两者之间的关联(这可能更复杂)。在大多数情况下,这将包括给定访问的 INP LoAF;在极少数情况下,如果不包含 INP LoAF,系统仍会显示需要解决的重要的长时间互动,因为它们可能是其他用户的 INP 互动。

以下代码会记录在帧期间发生互动且 blockingDuration 大于 100 毫秒的所有 LoAF 条目。这里选择 100,是因为它低于 200 毫秒的“良好”INP 阈值。您可以根据需要选择更高或更低的值。

const REPORTING_THRESHOLD_MS = 100;

const observer = new PerformanceObserver(list => {
  for (const entry of list.getEntries()) {
    if (entry.blockingDuration > REPORTING_THRESHOLD_MS &&
      entry.firstUIEventTimestamp > 0
    ) {
      // Example here logs to console, but could also report back to analytics
      console.log(entry);
    }
  }
});
observer.observe({ type: 'long-animation-frame', buffered: true });

观察长动画帧和较长的阻塞时长

为了改进查看包含互动的所有长动画帧的方式,您可能需要查看阻塞时长较长的所有长动画帧。如果用户在这些长动画帧期间进行互动,则这些指标表示可能存在 INP 问题。

以下代码会记录在帧期间发生互动且阻塞时长超过 100 毫秒的所有 LoAF 条目。这里选择 100 是因为它小于 200 毫秒的“良好”INP 阈值,有助于识别潜在的问题帧,同时最大限度地减少报告的长动画帧数量。您可以根据需要选择更高或更低的值。

const REPORTING_THRESHOLD_MS = 100;

const observer = new PerformanceObserver(list => {
  for (const entry of list.getEntries()) {
    if (entry.blockingDuration > REPORTING_THRESHOLD_MS) {
      // Example here logs to console, but could also report back to analytics
      console.log(entry);
    }
  }
});
observer.observe({ type: 'long-animation-frame', buffered: true });

观察关键界面更新期间的长动画帧,以提高流畅度

如前所述,查看长时间阻塞的动画帧有助于解决输入响应问题。但是,为了确保流畅性,您应查看所有具有较长 duration 的长动画帧。

由于这可能会产生大量噪声,因此您可能需要使用如下模式将对这些数据点的测量限制在关键点:

const REPORTING_THRESHOLD_MS = 100;

const observer = new PerformanceObserver(list => {
  if (measureImportantUIupdate) {
    for (const entry of list.getEntries()) {
      if (entry.duration > REPORTING_THRESHOLD_MS) {
        // Example here logs to console, but could also report back to analytics
        console.log(entry);
      }
    }
  }
});
observer.observe({ type: 'long-animation-frame', buffered: true });

async function doUIUpdatesWithMeasurements() {
  measureImportantUIupdate = true;
  await doUIUpdates();
  measureImportantUIupdate = false;
}

观察最长的动画帧

网站可能希望收集最长动画帧的数据,而不是设置阈值,以减少需要发送信标的数据量。因此,无论网页出现多少个长动画帧,系统只会回传最糟糕的 1 个、5 个、10 个或绝对必要的任意数量的长动画帧的数据。

MAX_LOAFS_TO_CONSIDER = 10;
let longestBlockingLoAFs = [];

const observer = new PerformanceObserver(list => {
  longestBlockingLoAFs = longestBlockingLoAFs.concat(list.getEntries()).sort(
    (a, b) => b.blockingDuration - a.blockingDuration
  ).slice(0, MAX_LOAFS_TO_CONSIDER);
});
observer.observe({ type: 'long-animation-frame', buffered: true });

这些策略也可以组合使用,例如只查看互动时间超过 100 毫秒的 10 个最差 LoAF。

在适当的时间(最好是在 visibilitychange 事件中)将信标发回到 Google Analytics。对于本地测试,您可以定期使用 console.table

console.table(longestBlockingLoAFs);

识别长动画帧中的常见模式

另一种策略是查看长动画帧条目中出现最多的常用脚本。系统可能会在脚本和字符位置级别报告数据,以便识别屡次违规的用户。

这对于可自定义的平台尤其适用,因为在这种平台上,您可以跨多个网站找出导致性能问题的主题或插件。

您可以汇总长动画帧中常见脚本(或第三方来源)的执行时间,并进行报告,以便找出导致某个网站或一组网站出现长动画帧的常见因素。例如,如需查看网址,请执行以下操作:

const observer = new PerformanceObserver(list => {
  const allScripts = list.getEntries().flatMap(entry => entry.scripts);
  const scriptSource = [...new Set(allScripts.map(script => script.sourceURL))];
  const scriptsBySource= scriptSource.map(sourceURL => ([sourceURL,
      allScripts.filter(script => script.sourceURL === sourceURL)
  ]));
  const processedScripts = scriptsBySource.map(([sourceURL, scripts]) => ({
    sourceURL,
    count: scripts.length,
    totalDuration: scripts.reduce((subtotal, script) => subtotal + script.duration, 0)
  }));
  processedScripts.sort((a, b) => b.totalDuration - a.totalDuration);
  // Example here logs to console, but could also report back to analytics
  console.table(processedScripts);
});

observer.observe({type: 'long-animation-frame', buffered: true});

输出示例如下:

(index) sourceURL count totalDuration
0 'https://example.consent.com/consent.js' 1 840
1 'https://example.com/js/analytics.js' 7 628
2 'https://example.chatapp.com/web-chat.js' 1 5

在工具中使用 Long Animation Frames API

该 API 还支持使用其他开发者工具进行本地调试。虽然 Lighthouse 和 Chrome DevTools 等一些工具能够使用更低级的跟踪详细信息收集其中的大部分数据,但有了这个更高级的 API,其他工具也能访问这些数据。

在开发者工具中显示长动画帧数据

您可以使用 performance.measure() API 在 DevTools 中显示长动画帧,这些帧随后会显示在性能轨迹的 DevTools 用户时间轨迹中,以显示您应在哪些方面着力改进性能。使用 DevTools Extensibility API,这些内容甚至可以在自己的轨道中显示:

const observer = new PerformanceObserver((list) => {
  for (const entry of list.getEntries()) {
    performance.measure('LoAF', {
      start: entry.startTime,
      end: entry.startTime + entry.duration,
      detail: {
        devtools: {
          dataType: "track-entry",
          track: "Long animation frames",
          trackGroup: "Performance Timeline",
          color: "tertiary-dark",
          tooltipText: 'LoAF'
        }
      }
    });
  }
});

observer.observe({ type: 'long-animation-frame', buffered: true });
包含自定义轨道的 DevTools 性能面板轨迹,其中显示了可与主火焰图表进行比较的“长动画帧”数据。
在 DevTools 中显示较长的动画帧数据。

从长远来看,长动画帧可能会被纳入到 DevTools 本身,但在此期间,您可以使用上一个代码段在 DevTools 中显示长动画帧。

上图中的第一条记录还展示了浏览器在哪些位置在同一长动画帧中一起处理了多个任务,而不是在这些任务之间进行渲染。如前所述,当没有高优先级输入任务,但有任务队列时,就可能会发生这种情况。第一个长任务需要完成一些渲染更新(否则,当前的长动画帧会在完成后重置,并在下一个任务开始时开始新的长动画帧),但浏览器并未立即执行该渲染,而是处理了一些其他任务,然后才执行长渲染任务并结束长动画帧。这说明,在 DevTools 中查看长动画帧(而不仅仅是长任务)有助于发现延迟渲染。

在其他开发者工具中使用长动画帧数据

Web Vitals 扩展程序已在日志摘要调试信息中显示该值,以便诊断性能问题。

现在,它还会显示每个 INP 回调和每次互动所对应的长动画帧数据:

Web Vitals 扩展程序控制台日志记录。
“网页指标”扩展程序控制台日志记录会显示 LoAF 数据。

在自动化测试工具中使用长动画帧数据

同样,CI/CD 流水线中的自动化测试工具可以在运行各种测试套件时衡量长动画帧,从而显示潜在性能问题的详细信息。

常见问题解答

有关此 API 的一些常见问题包括:

为什么不直接扩展或迭代 Long Tasks API?

这是一种报告类似(但最终不同的)潜在响应能力问题的替代方法。请务必确保依赖现有 Long Tasks API 的网站能够继续正常运行,以免影响现有用例。

虽然 Long Tasks API 可能会受益于 LoAF 的一些功能(例如更好的归因模型),但我们认为,专注于帧而非任务会带来诸多好处,这使得该 API 与现有的 Long Tasks API 截然不同。

为什么我没有脚本条目?

这可能表明动画帧延迟时间长的原因不是 JavaScript,而是大量渲染工作。

如果长动画帧由 JavaScript 导致的,但由于前面提到的各种隐私保护原因(主要是 JavaScript 不归网页所有),无法提供脚本提供方信息,也可能会出现这种情况。

为什么我有脚本条目,但没有来源信息或来源信息有限?

导致这种情况的原因有很多,包括没有合适的来源可供指向

对于 no-cors cross-origin 脚本,脚本信息也将仅限于 sourceURL(不包括任何重定向),sourceFunctionName 为空字符串,sourceCharPosition-1。您可以通过将 crossOrigin = "anonymous" 添加到 <script> 调用,使用 CORS 提取这些脚本来解决此问题。

例如,要添加到网页中的默认 Google 跟踪代码管理器脚本:

<!-- Google Tag Manager -->
<script>(function(w,d,s,l,i){w[l]=w[l]||[];w[l].push({'gtm.start':
new Date().getTime(),event:'gtm.js'});var f=d.getElementsByTagName(s)[0],
j=d.createElement(s),dl=l!='dataLayer'?'&l='+l:'';j.async=true;j.src=
'https://www.googletagmanager.com/gtm.js?id='+i+dl;f.parentNode.insertBefore(j,f);
})(window,document,'script','dataLayer','GTM-XXXXXXX');</script>
<!-- End Google Tag Manager -->

可以通过添加 j.crossOrigin = "anonymous" 进行增强,以便为 GTM 提供完整的归因详细信息。

这是否会取代 Long Tasks API?

虽然我们认为 Long Animation Frames API 是用于衡量长任务的更好、更完整的 API,但目前没有计划废弃 Long Tasks API。

期待反馈

您可以在 GitHub 问题列表中提供反馈,也可以在 Chrome 问题跟踪器中提交 Chrome 实现的 API 中的 bug。

总结

Long Animation Frames API 是一款令人兴奋的新 API,与之前的 Long Tasks API 相比,它具有许多潜在优势。

事实证明,它是解决 INP 衡量的响应速度问题的关键工具。INP 是一个难以优化的指标,Chrome 团队正努力通过此 API 帮助开发者更轻松地发现和解决问题。

不过,Long Animation Frames API 的范围不仅仅局限于 INP,它还可以帮助找出导致更新缓慢的其他原因,这些原因可能会影响网站用户体验的整体顺畅度。

致谢

缩略图图片:Unsplash 用户 Henry Be