《经济时报》挑战 INP 问题

《Ecomonic Times》将 TBT 缩短了 30 次并迁移到 Next.js,这帮助 The Ecomonic Times 将 INP 降低了将近 4 倍,从而使跳出率降低了 50%,网页浏览量提升了 43%。

Daya Ram Yadav
Daya Ram Yadav
Saurabh Rajpal
Saurabh Rajpal

Interaction to Next Paint (INP) 是一项指标,用于评估网站对用户输入的响应速度。响应速度快意味着网页能够快速响应用户互动。网页的 INP 越低,对用户互动的响应能力就越好。

INP 值在 200 毫秒或更低时为良好,超过 500 毫秒时为不佳,介于两者之间的值则需要改进。

迷幻的开始

当 Google 最初将 INP 作为一项实验性指标推出时,它有可能演变为核心网页指标之一。由于提供世界一流的用户体验对我们的核心业务价值至关重要,因此《经济时报》团队接受了这一挑战,在 INP 成为核心网页指标之前对其进行了修正。

INP 一直是迄今为止最难解决的指标之一。起初,我们不确定如何有效衡量 INP。让问题变得更加困难的是缺少社区支持,包括大多数真实用户监控 (RUM) 提供商尚不支持此功能。不过,我们有 Chrome 用户体验报告 (CrUX)web-vitals JavaScript 库 等 Google RUM 工具和其他支持工具,这让我们在评估未来的发展方向时,能够了解目前的状况。刚开始时,我们的 INP 在源级别接近 1,000 毫秒。

现场修复 INP 时,我们发现可定位的一个实验室指标是 Total Blocking Time (TBT)。TBT 已经有详细的文档,并得到了社区的支持。不过,尽管已经达到了核心 Web 指标的阈值,但在 TBT 方面,我们表现不佳,因为在开始时,该指标超过了 3 秒。

什么是 TBT?我们采取了哪些措施来改进它?

TBT 是一项实验室指标,用于衡量网页在网页加载过程中对用户输入的响应情况。任何执行时间超过 50 毫秒的任务都被视为耗时较长的任务,超过 50 毫秒阈值的时间称为阻塞时间

TBT 的计算方法是:取网页加载期间所有耗时较长的任务的阻塞时间总和。例如,如果加载期间有两个长任务,则阻塞时间的确定方式如下:

  • 任务 A 用时 80 毫秒(30 毫秒比 50 毫秒多)。
  • 任务 B 用时 100 毫秒(50 毫秒比 50 毫秒多)。

网页的 TBT 为 80 毫秒(30 + 50)。TBT 越低越好,并且 TBT 与 INP 之间也存在很强的相关性

下面的实验简要比较了采取措施改进 TBT 前后的效果:

启动期间长任务的复合图片(如 Chrome DevTools 的“Performance”面板中所示),以及网页指标报告。主线程在网页加载期间阻塞了 3,260 毫秒。
优化 TBT 之前,启动期间的主线程。TBT 为 3,260 毫秒。
启动期间长时间运行的任务的合成图片(如 Chrome 开发者工具的性能面板中所示),以及页面指标的报告。主线程在网页加载期间会阻塞 120 毫秒。
优化 TBT 后,启动期间的主线程。TBT 为 120 毫秒。

最大限度地减少主线程工作

浏览器的主线程负责处理从解析 HTML、构建 DOM 到解析 CSS 和应用样式,以及评估和执行 JavaScript 的所有事务。主线程还处理用户互动,即点击、点按和按键。如果主线程正忙于执行其他工作,它可能无法有效地响应用户输入,并且可能导致用户体验卡顿。

这对我们来说是最难的任务,因为我们有自己的算法来检测用户身份,以便根据订阅状态投放广告,并使用第三方脚本进行 A/B 测试、分析等。

我们一开始采取的是小步措施,例如降低加载不太重要的业务资源的优先级。其次,我们使用 requestIdleCallback 来执行非关键工作,这有助于缩短 TBT。

if ('requestIdleCallback' in window) {
  this.requestIdleCallbackId = requestIdleCallback(fetchMarketsData.bind(this), {timeout: 3000});
} else {
  fetchMarketsData(); // Fallback in case requestIdleCallback is not supported
}

建议在使用 requestIdleCallback 时指定超时时间,因为这样可以确保如果给定时间已过,但尚未调用回调,则在超时后立即执行回调。

最大限度地缩短脚本评估时间

我们还使用可加载的组件延迟加载第三方库。我们还使用 Chrome 开发者工具中的覆盖率工具对网页进行性能分析,移除了未使用的 JavaScript 和 CSS。它帮助我们确定了需要进行摇树优化的区域,以便在页面加载期间减少代码数量,从而减少应用的初始软件包大小。

Chrome DevTools 中覆盖率工具的屏幕截图。在这里,该工具会显示网页加载期间 JavaScript 和 CSS 文件的未使用部分。

缩减 DOM 大小

根据 Lighthouse 的说法,DOM 大小过大会增加内存用量、导致样式重新计算用时延长,并产生高昂的布局自动重排费用。

Lighthouse 中 DOM 大小审核的屏幕截图。报告的 DOM 元素数量为 2,706 个元素。

我们通过以下两种方式减少了 DOM 节点的数量:

  • 首先,我们应用户的请求(点击时)呈现菜单项。这会将 DOM 大小缩减约 1,200 个节点。
  • 其次,我们延迟加载了重要性较低的 widget。

通过所有这些努力,我们大幅减少了 TBT,并将 INP 降低了近 50%:

CrUX 中的 INP 审核的屏幕截图。网页的 INP 为 539 毫秒,超出了“欠佳”阈值。

至此,我们几乎没有可以轻松实现的措施来进一步降低 TBT(以及通过代理降低 INP),但我们知道自己还有很大的改进空间。因此,我们决定将自定义界面样板升级到最新版本的 React 和 Next.js,以便更好地利用钩子来避免不必要地重新渲染组件。

由于与网站的其他部分相比,更新频率和流量相对较少,因此我们开始将主题页面迁移到 Next.js。我们还使用 PartyTown 将额外的繁重主线程工作分流给 Web Worker,并采用 requestIdleCallBack 等技术来延迟非关键任务。

提高 INP 对《经济时报》有何帮助?

来源的当前 TBT 和 INP

在发布这篇文章时,我们源站的 TBT 为 120 毫秒,比我们开始优化时的 3,260 毫秒缩短了许多。同样,在我们进行优化后,源的 INP 从超过 1,000 毫秒降到了 257 毫秒。

CrUX 中的 INP 审核的屏幕截图。该网页的 INP 为 257 毫秒,属于“需要改进”阈值范围内。

INP CrUX 趋势

主题页面获得的流量在总流量中所占的比例要小得多。因此,这是一个理想的实验场所。CrUX 带来的成效和业务成果非常令人鼓舞,这促使我们在整个网站上扩大了改进力度,以期进一步受益。

一张屏幕截图,显示了 2022 年 7 月至 2022 年 10 月这四个月内 INP 分布情况(在 CrUX 中可视化)。“较差”和“有待改进”阈值范围内的值有所下降,而“良好”阈值范围内的值有所上升。

Akamai mPulse TBT 分析

我们使用 Akamai mPulse 作为我们的 RUM 解决方案,可在现场测量 TBT。我们观察到 TBT 持续下降,这与减少 INP 所取得的成效明确对应。如以下屏幕截图所示,在现场测试中,TBT 值最终从大约 5 秒降至大约 200 毫秒。

Akamai mPulse 中一张图表的屏幕截图,显示了 TBT 在约一个月的时间里有所下降。

业务成效

总体而言,我们将 TBT 缩短了 30 倍,并迁移到了 Next.js,这两项举措帮助我们将 INP 缩短了近 4 倍,最终导致主题页面的跳出率降低了 50%,网页浏览量提高了 43%

Google Analytics 的屏幕截图,比较了网页浏览量与跳出率。由于对《经济时报》网站上的 INP 进行了优化,跳出率降低了 50%,网页浏览量增加了 43%。

总结

总而言之,INP 帮助我们全面确定了《经济时报》网站的某些部分存在的运行时性能问题。事实证明,它是对业务成果产生积极影响的最有效指标之一。由于我们在执行这项工作后取得了非常令人鼓舞的结果,因此我们有动力将优化工作扩展到网站的其他方面,从而获得更多好处。