在实验室中手动诊断互动速度缓慢的问题

了解如何将现场数据导入实验室,以通过手动测试重现互动缓慢并确定互动缓慢的原因。

优化 Interaction to Next Paint (INP) 时,一个具有挑战性的环节是找出导致 INP 不佳的原因。有很多的潜在原因:第三方脚本在主线程上调度许多任务,DOM 大小较大、事件回调开销高,等等。

想方设法解决 INP 不佳的问题可能并不容易。首先,您必须了解哪些互动往往导致网页的 INP。如果您不知道从真实用户的角度来看,您网站上哪些互动的执行速度往往最慢,请先阅读查找现场缓慢的互动。获得实测数据作为指导后,您就可以在实验室工具中手动测试这些特定交互,从而找出这些交互速度缓慢的原因。

如果没有现场数据怎么办?

拥有现场数据至关重要,因为这可以为您节省大量时间来思考需要优化哪些互动。但是,您可能没有字段数据。如果您的情况符合以上描述,您还是有可能找到可改善的互动,但需要付出更多的努力并采用不同的方法。

Total Blocking Time (TBT) 是一项实验室指标,用于评估页面在加载期间的响应速度,与 INP 非常相关。如果您的网页的 TBT 较高,这可能表示您的网页在初始网页加载期间对用户互动的响应速度可能不够快。

要确定网页的 TBT,您可以使用 LighthousePageSpeed Insights。如果网页的 TBT 值未达到“良好”阈值,则很有可能主线程在网页加载期间过于繁忙,这可能会影响在网页生命周期中的关键时间内进行互动的速度。

若要在网页加载找出互动速度缓慢的问题,您可能需要依赖其他类型的数据,例如您可能已经在网站的分析数据中发现的常见用户流。例如,如果您处理的是电子商务网站,常见的用户流是指用户在将商品添加到在线购物车并随后完成结账流程时执行的操作。

无论您是否有现场数据,下一步都是手动测试并重现慢速互动,因为只有您能够最终确定一个慢速互动时才能进行修正。

重现实验室中缓慢的互动

您可以通过多种方式在实验室中通过手动测试重现缓慢互动问题,但下面提供的框架可以帮助您在尽可能减少认知工作量的同时,重现实验室环境中的缓慢互动问题。

不要立即使用性能分析器

如果您已经熟悉 Chrome 的性能分析器,就会知道它在排查网页性能问题时提供了大量有用的诊断信息。这款工具很实用,有很多优点。

但缺点是,Chrome 的性能分析器在与网页交互时不提供实时视图。使用起来需要花费大量时间,并且可以通过更高效的方法先手动测试互动。其理念是尽可能花费最少的时间和精力来重现缓慢互动,在最终确定慢互动后,您应使用性能分析器深入了解其背后的原因。

使用 Chrome 扩展程序“Web Vitals”

在手动测试互动延迟时间方面,Web Vitals Chrome 扩展程序的工作量最少。安装后,如果您首先执行以下操作,此扩展程序将在 DevTools 控制台中显示互动数据:

  1. 在 Chrome 中,点击地址栏右侧的扩展程序图标。
  2. 在下拉菜单中找到 Web Vitals 扩展程序。
  3. 点击右侧的图标,打开扩展程序的设置。
  4. 点击选项
  5. 在出现的屏幕中选中控制台日志记录复选框,然后点击保存

完成此操作后,在 Chrome 开发者工具中打开控制台,然后开始测试您网站上的疑似互动。当您与页面交互时,有用的诊断数据会显示在控制台中。

Web Vitals 扩展程序为互动提供的控制台日志记录屏幕截图。该日志记录包含时间和其他上下文信息等详细信息。
开启控制台日志记录时,Web Vitals 扩展程序中的控制台条目。每次符合条件的互动都会在控制台中记录互动数据。

使用 JavaScript 代码段

Web Vitals 扩展程序虽然可能非常有用,但并非人人皆宜。根据设备安全政策,浏览器扩展程序在某些环境中可能会被屏蔽。也无法在移动设备上安装扩展程序。如果您想使用远程调试在 Android 实体设备上手动测试,第二种方法会带来问题。

使用 Web Vital 扩展程序的另一种方法是将一些 JavaScript 复制并粘贴到开发者工具控制台中。对于每次互动,以下代码都会提供与 Web Vitals 扩展程序相同的控制台输出:

let worstInp = 0;

const observer = new PerformanceObserver((list, obs, options) => {
  for (let entry of list.getEntries()) {
    if (!entry.interactionId) continue;

    entry.renderTime = entry.startTime + entry.duration;
    worstInp = Math.max(entry.duration, worstInp);

    console.log('[Interaction]', entry.duration, `type: ${entry.name} interactionCount: ${performance.interactionCount}, worstInp: ${worstInp}`, entry, options);
  }
});

observer.observe({
  type: 'event',
  durationThreshold: 0, // 16 minimum by spec
  buffered: true
});

确定某次互动的速度非常慢后,您可以在性能分析器中分析该互动的速度,以详细了解该互动速度缓慢的原因。

如果无法重现缓慢的互动,该怎么办?

如果您的实地数据表明某个互动速度很慢,但您无法手动重现实验问题,该怎么办?导致这种情况的原因有很多,这也是排查任何类型的性能问题时遇到的常见问题。

一次,测试互动时所处的环境取决于您所使用的硬件和网络连接。毕竟,您使用的可能是通过快速连接的快速设备,但这并不意味着您的用户就如此幸运。如果您的情况符合上述情况,您可以执行以下三项操作之一:

  1. 如果您使用的是 Android 实体设备,请使用远程调试在主机上打开 Chrome 开发者工具实例,并尝试在主机上重现缓慢互动问题。移动设备的速度通常不如笔记本电脑或台式机,因此在此类情况下,更容易观察到互动速度较慢。
  2. 如果您没有实体设备,请在 Chrome 开发者工具中启用 CPU 节流功能
  3. 请同时尝试执行第 1 步和第 2 步,因为您也可以在 Android 实体设备上对开发者工具启用 CPU 节流。

另一个原因可能是,您在等待页面加载后再与页面交互,但用户没有等待。如果您使用的是速度较快的网络,请启用网络节流功能来模拟较慢的网络状况,然后在网页呈现后立即与该网页互动。您应该这样做,因为主线程在启动期间通常最繁忙,此时的测试可能会揭示用户所经历的情况。

录制轨迹

如需详细了解互动速度缓慢的原因,下一步是使用 Chrome 开发者工具中的性能分析器。如需在 Chrome 的性能分析器中分析互动情况,请执行以下操作:

  1. 打开您需要测试的网页。
  2. 打开 Chrome 开发者工具,然后转到性能面板。
  3. 点击面板左上角的 Record 按钮可开始跟踪。
  4. 执行您要分析的互动。
  5. 再次点击 Record 按钮可停止跟踪。

当性能分析器填充时,应先查看性能分析器顶部的 activity 摘要。活动摘要会在记录中发生长时间运行的任务的顶部显示红条。这使您可以快速放大问题区域。

Chrome 开发者工具性能面板中活动摘要的屏幕截图。显示的 activity 主要来自 JavaScript,该 activity 会导致冗长的任务,该任务在火焰图上方以红色突出显示。
Chrome 性能分析器顶部的活动摘要。长时间运行的任务在活动火焰图上方以红色突出显示。在这种情况下,长时间运行的任务中的大部分工作是由大量的脚本工作导致的。

您可以通过在 activity 摘要中拖动并选择某个区域来快速关注有问题的区域。当您重点关注互动发生的位置后,Interactions 轨道可以帮助您将互动与在其下方的主线程轨道中发生的活动对应起来:

Chrome 开发者工具的性能面板中可视化的互动屏幕截图。主线程轨道上方的互动跟踪记录会显示互动的时长,可与主线程活动一起显示。
Chrome 开发者工具的性能分析器中分析的交互。 Interactions 轨道会显示一系列与点击互动对应的事件。Interactions 跟踪的条目跨越负责驱动交互的任务。

从这里开始,就要深入探究导致互动缓慢的问题。导致高互动延迟时间的原因有很多,本指南将对其中一些进行详细介绍。

使用 Lighthouse 时间跨度作为跟踪的替代方案

Chrome 的性能分析器虽然包含丰富的诊断信息,但对初学者而言可能有点望而生畏。Lighthouse 的时间跨度模式是性能分析器的一种替代方案。如需使用此模式,请执行以下操作:

  1. 打开开发者工具后,前往开发者工具中的 Lighthouse 标签页。
  2. 模式部分下,选择时间范围选项。
  3. 设备部分下,选择桌面设备移动设备设备类型。
  4. 确保至少选中类别标签下标记为性能的复选框。
  5. 点击开始时间跨度按钮。
  6. 在您想要获取数据的页面上测试互动。
  7. 点击结束时间范围按钮,然后等待系统显示审核结果
  8. 在 Lighthouse 标签页中填充审核结果后,您可以点击 Show reviews related to 标签旁边的 INP 链接,按 INP 过滤审核结果。

此时,您应该会看到已失败或已通过的审核的下拉列表。展开该下拉菜单后,您应该会看到互动期间所花时间的明细。

由时间跨度模式提供的 Lighthouse 审核的屏幕截图。此项评估专门用于 INP,它会提供互动的详细信息,包括触发互动的元素的屏幕截图,以及详细列出了处理互动所花时间的表格。
在 Lighthouse 的时间跨度模式下分析的交互。在用户与页面进行互动时,Lighthouse 会提供一项审核服务,详细说明互动期间所花时间的位置,并按输入延迟、处理延迟和呈现延迟对其进行细分。

如何识别较长的输入延迟

输入延迟是可能会导致互动延迟增加的因素之一。输入延迟是互动的第一阶段。从操作系统首次收到用户操作到浏览器能够开始处理该输入触发的第一个事件之间的时长。输入延迟会在互动的事件回调开始运行后立即结束。

若要确定 Chrome 性能分析器中的输入延迟,您可以在互动轨道中找到相应互动的开始时间,然后找到该互动的事件回调开始运行的时间。

一定程度的输入延迟应该始终是正常的,因为操作系统需要一些时间将输入事件传递给浏览器,但您可以一定程度地控制输入延迟的长短。关键是确定主线程上是否有作业正在阻止回调运行。

描绘 Chrome 性能面板中的输入延迟。由于第三方脚本触发的计时器导致输入延迟增加,因此互动的开始时间明显早于事件回调的开始时间。
由第三方脚本的计时器触发的任务导致的输入延迟。

在上图中,当用户尝试与页面互动时,第三方脚本中的任务正在运行,因此会延长输入延迟。扩展输入延迟会影响互动的延迟时间,进而影响网页的 INP。

如何识别开销很高的事件回调

事件回调会在输入延迟后立即运行。如果事件回调的运行时间过长,会导致浏览器延迟呈现下一帧,并且可能会显著增加互动的总延迟时间。长时间运行的事件回调可能是计算成本高昂的第一方或第三方 JavaScript(在某些情况下,两者兼有)所导致。

描绘 Chrome 性能面板中的事件回调任务。按下指针和点击事件(发生在较长的任务中)会发生事件回调。
为响应点击互动而运行的事件回调函数,如 Chrome 开发者工具中的性能分析器所示。请注意 Event: pointerdownEvent: click 条目右上角的红色三角形,其标识开销非常大的事件回调。

通过在特定互动的跟踪记录中观察以下内容,可以找出开销高昂的事件回调:

  1. 确定与事件回调相关联的任务是否为长任务。为了更可靠地在实验室设置中发现耗时较长的任务,您可能需要在性能面板中启用 CPU 节流,或者连接中低层级的 Android 设备并使用远程调试
  2. 如果运行事件回调的任务是一项长任务,请在调用堆栈中查找事件处理程序条目(例如名称如 Event: click 的条目),且条目的右上角有红色三角形。这些事件回调的成本很高。

如需解决开销很高的事件回调,请尝试以下策略之一:

  1. 尽可能少做工作。在成本高昂的事件回调中发生的所有操作是否都绝对必要?如果没有,请考虑尽可能将相关代码完全移除;如果无法执行,则推迟到晚些时候执行。您还可以利用框架功能来实现此目的。例如,当组件的属性和状态未更改时,React 的 PureComponent记忆功能可以跳过不必要的渲染工作。
  2. 将事件回调中的非渲染工作推迟到以后的时间点。 您可通过让出于主线程来分解长任务。每当您让出主线程时,您就会结束当前任务的执行,并将其余工作拆分成一个单独的任务。这样,渲染程序就有机会处理之前在事件回调中执行的界面更新。如果您碰巧正在使用 React,其过渡功能可以帮您实现此目的。

通过采用这些策略,您应该能够在能够更快地响应用户输入的位置获得事件回调。

如何确定呈现延迟

输入延迟和开销高的事件回调并不是导致 INP 不佳的唯一原因。有时,为响应少量事件回调代码而发生的渲染更新可能成本高昂。浏览器将视觉更新呈现给界面以反映互动结果所需的时间称为“呈现延迟”。

渲染工作在 Chrome 开发者工具的性能面板中以可视化方式呈现。为了绘制下一帧,渲染工作发生在事件回调之后。
Chrome 性能分析器中显示的渲染任务。渲染工作以紫色显示,绘制工作以绿色显示。

在所有可能的高互动延迟原因中,渲染工作可能最难以进行问题排查和修复,但结果是值得的。以下任何原因都可能会导致渲染工作过多:

  • DOM 大小。更新网页呈现方式所需的渲染工作通常会随网页 DOM 的大小而增加。如需了解详情,请参阅 DOM 大小对互动性的影响以及您可以采取的措施
  • 强制自动重排 -当您将样式更改应用于 JavaScript 中的元素,然后查询该工作的结果时,就会发生这种情况。结果是,浏览器必须先执行布局工作,然后才能执行任何其他操作,以便浏览器能够返回更新后的样式。有关如何避免强制自动重排的更多信息和提示,请参阅避免大型、复杂的布局和布局抖动
  • requestAnimationFrame 回调中过多或不必要的工作。 requestAnimationFrame() 回调在事件循环的渲染阶段运行,且必须在显示下一帧之前完成。请注意,如果您使用 requestAnimationFrame() 执行与界面更改无关的工作,则可能会延迟下一帧。
  • ResizeObserver 回调。此类回调在渲染之前运行,并且如果其中的工作开销很高,则可能会延迟下一帧的呈现。与事件回调一样,请推迟下一帧不需要的任何逻辑。

INP 问题排查是一个迭代过程

找出导致 INP 不佳导致互动延迟高的原因需要完成大量的工作,但如果您能找到原因,那就已经完成了一半。通过有条理地排查 INP 不佳问题,您可以可靠地找出问题根源,并更快地找到正确的修复方法。如需查看:

  • 依靠实测数据找出缓慢的互动
  • 在实验室中手动测试有问题的现场交互,看看它们是否可重现。
  • 确定导致输入延迟过长、事件回调开销高或渲染工作开销高的原因。
  • 重复。

最后一点是最重要的。与为提高网页性能所做的大多数其他工作一样,排查和改进 INP 是一个周期性过程。解决一个互动缓慢问题后,继续进行下一个互动,然后重复上述操作,直到看到结果为止。保持警惕!