维度:加载状态 INP (inpls)
加载状态 (INP) 维度记录了捕获用户交互那一刻的文档就绪状态。Chrome 用户体验报告中的每个 INP 事件都带有一个加载状态标签:loading、dom-interactive、dom-content-loaded 或 complete 之一。CoreDash 将该标签呈现为一个可过滤、可分组的维度,以便你回答原始 INP 得分无法回答的问题:最糟糕的交互发生在页面生命周期的哪个阶段?
这个问题是两种完全不同的工程修复方案的分水岭。聚集在 loading 阶段的 INP 问题需要采用 JavaScript 延迟加载策略。聚集在 complete 阶段的 INP 问题则需要减少事件处理程序的工作量、降低框架开销,或在运行时代码中拆分 long task。按加载状态分组可以直接帮你切分这两种情况,无需任何手动插桩。
在被监控网站的 CoreDash 数据中,按加载状态划分 of INP 交互分布大致为:loading 占 15%、dom-interactive 占 20%、dom-content-loaded 占 25%、complete 占 40%。大多数交互发生在页面完全加载之后,但最糟糕的 INP 得分绝大多数都聚集在早期状态。
屏幕截图

为什么加载状态对 INP 至关重要
Interaction to Next Paint 指标测量用户交互的完整延迟:输入延迟、事件处理程序执行时间,以及到下一帧绘制的呈现延迟。在这三个组成部分中,输入延迟最直接受用户点击或轻触时浏览器正在执行的操作所控制。
在页面加载早期,main thread 处于极度繁忙的竞争状态。浏览器正在解析 HTML、执行同步脚本、构建 CSSOM、运行 render blocking 资源,并接连触发渲染周期。main thread 上的每个 long task 都是一个窗口期,在此期间用户交互会被排队等待。这种等待就是输入延迟,它是页面加载期间 INP 表现不佳的主要原因。
在 document.readyState 达到 complete 之后发生的交互,所面对的 main thread 会空闲很多。浏览器已完成加载。如果在该阶段 INP 仍然很差,原因就不是加载时的资源竞争。而是你的页面在响应用户操作时运行的 JavaScript 导致的:臃肿的事件处理程序、框架的重复渲染周期、脚本触发的布局抖动(layout thrashing),或者在交互期间同步执行的未优化第三方代码。
加载状态是区分这两种根本原因最快的方法。
加载状态详解
loading
页面尚未完成 HTML 文档的解析。main thread 正在执行同步脚本、获取 parser-blocking 资源并构建初始 DOM。这是对用户交互最不利的环境。输入延迟处于最高水平,因为任何 long task 都会直接阻碍浏览器处理点击或轻触。在此窗口期进行交互的用户通常是最没有耐心的访客,或者是那些使用快速连接、在页面完成加载前就已经看到可见内容的访客。他们所产生的 INP 得分将是你收集到的数据中最糟糕的。如果在你表现较差的 INP 事件中,有相当大的一部分带有 loading 状态,请将非关键脚本改为 defer 或 async,并消除首屏(above the fold)的 parser-blocking 资源。
dom-interactive
当 HTML 解析完成且 DOM 构建完毕时,document.readyState 会达到 interactive,但此时图片、样式表和延迟脚本等子资源仍在加载。延迟脚本在此时开始执行,这意味着 main thread 仍可能非常繁忙。框架 hydration 通常在此处开始。这是一个危险的窗口期,因为页面看起来已经准备就绪,但 main thread 实际上仍然很忙。输入延迟依然处于高位。如果糟糕的 INP 集中在此处,修复方法与 loading 相同:减少 DOM 解析完成后立即运行 the 同步工作量。
dom-content-loaded
DOMContentLoaded 事件已经触发。DOM 构建完毕,且延迟脚本也已执行。此时大多数 JavaScript 框架已完成了初始 hydration。main thread 的工作负载开始下降,交互的响应速度开始变快。在此状态下的 INP 得分通常好于前两个状态,但与 complete 相比仍然偏高。如果看到差的交互集中在这里,请检查你的框架或应用脚本在 DOMContentLoaded 处理程序中执行了什么操作,以及 hydration 工作是否可以分块或 yield,以便在任务之间处理输入。
complete
当包含图片、字体和第三方 iframe 在内的所有资源都加载完毕时,document.readyState 会达到 complete。这是页面在后续会话中运行的稳定状态。在此状态下表现较差的 INP 纯粹是一个运行时问题。页面已加载完毕。如果 main thread 仍在阻塞交互,则原因在于交互期间的 JavaScript 执行:事件处理程序执行了太多的同步工作、框架更新触发了昂贵的布局重新计算,或者第三方脚本在持续运行 long task。此时的解决办法不是延迟加载,而是降低用户实际点击时所发生的操作开销。
调试工作流
第一步:在 CoreDash 中按加载状态进行过滤。打开 INP 细分表,并按加载状态分组。找出哪个状态所占的较差交互(超过 200ms)比例最高。这能让你立即判断出面对的是加载问题还是运行时问题。
第二步:结合 URL 和设备进行交叉对比。将加载状态维度与 URL 维度结合起来,找出哪些特定页面在早期加载状态下会产生较差的交互。移动设备在加载期间受到的影响要大得多,因为较慢的 CPU 会延长每个 long task。
第三步:针对具体状态进行修复。对于 loading 和 dom-interactive,请参考 Optimize INP 指南 来评估你的脚本加载策略。将脚本移至 defer,消除 render blocking 资源,并使用 scheduler.yield() 拆分长初始化任务。对于 complete,请在 Chrome DevTools 中分析你的事件处理程序,并减少它们在每次交互中触发的同步工作。
工程经验法则
如果超过 30% 的较差 INP 交互被标记为 loading 或 dom-interactive,那么你的 INP 问题就是页面加载问题,延迟加载 JavaScript 将带来最明显的改善。如果超过 60% 的较差交互被标记为 complete,那么你的 INP 问题就是运行时问题,你需要优化事件处理程序的成本,而不是脚本加载顺序。加载状态 (INP) 能在一个表格视图中为你做出这一判断,无需进行实验室分析或自定义插桩。