代表性面试主题

如何用 firstInterimResponseStart 衡量 Early Hints 的真实收益?

前端中等
Offer.cc 编辑团队发布 更新

题干

请实现一个前端性能观测器,统计资源收到首个 1xx 响应的时间,并说明如何区分 103 Early Hints、缓存、跨源遮蔽和浏览器不支持。

题目与背景

浏览器开始支持 PerformanceResourceTiming.firstInterimResponseStart,它记录收到首个临时 1xx 响应字节的时间。请实现观测逻辑,评估 103 Early Hints 是否缩短资源准备时间,并处理不支持、跨源和缓存场景。

面试官考察什么

  • 是否理解 requestStartfirstInterimResponseStart 与最终响应头时间的关系。
  • 是否知道 0 既可能表示没有 1xx,也可能来自跨源时序遮蔽或缓存。
  • 是否能用 PerformanceObserver 处理 buffered 条目和上报采样。
  • 是否能把协议收益与浏览器兼容、Timing-Allow-Origin 和业务指标分开。

先问清楚的澄清问题

观测目标

要衡量的是收到 1xx 的等待时间、Early Hints 触发的预加载数量,还是最终 LCP、首屏可交互时间?

资源范围

只观测同源主导航,还是包含 CDN、字体和跨源脚本?跨源响应是否配置 Timing-Allow-Origin

兼容性策略

数据是否用于实时决策?旧浏览器和不支持该属性的浏览器是否必须提供同等降级指标?

30 秒回答框架

我会用 PerformanceObserver 读取资源条目,在属性存在且值大于零时计算 firstInterimResponseStart - requestStart。零值不能直接判定服务器没发 103,因为跨源时序可能被遮蔽,缓存也会给出零。观测系统要记录支持能力、资源同源性和最终响应时间,并用 LCP 等用户指标验证 Early Hints 是否真的带来收益。

深入解答步骤

1. 说明时间点语义

requestStart 表示浏览器即将发出资源请求的时间;firstInterimResponseStart 表示收到首个 1xx 响应的首字节时刻;finalResponseHeadersStart 表示最终响应头到达。若存在临时响应,firstInterimResponseStart - requestStart 可近似首个 1xx 的网络等待。

2. 写出观测器

js
const observer = new PerformanceObserver((list) => {
  for (const entry of list.getEntries()) {
    const interim = entry.firstInterimResponseStart;
    if (typeof interim !== "number" || interim <= 0) continue;

    reportTiming({
      name: entry.name,
      interimWait: interim - entry.requestStart,
      finalHeaders: entry.finalResponseHeadersStart - interim,
      initiator: entry.initiatorType,
    });
  }
});

observer.observe({ type: "resource", buffered: true });

生产代码应先做属性检测,并限制资源名称、采样率和上报字段,避免把完整 URL 或敏感查询参数发送到分析系统。

3. 解释零值

值为 0 可能表示没有临时响应,也可能表示跨源资源没有通过 Timing-Allow-Origin 暴露时序;缓存命中和取消请求也可能使相关时刻为 0。因此仪表盘应把“未观测到”与“确认没有 1xx”分开,不要用零值计算负数或直接标记失败。

4. 处理跨源资源

若 CDN 或字体来自其他源,服务端需要对允许的站点返回 Timing-Allow-Origin,浏览器才会暴露受保护的计时字段。该响应头必须按实际部署的源配置,不能为所有来源开放;同时仍要接受部分用户因策略不同而不可观测。

5. 区分 103 与最终收益

该属性告诉你收到某个 1xx 的时间,不直接证明它是 103,也不证明预加载资源被使用。结合导航请求、服务器日志或受控实验确认 103,再比较 finalResponseHeadersStart、资源 responseEnd 和 LCP。若预加载过早或命中错误资源,首个 1xx 变快也可能让性能变差。

6. 设计兼容降级

不支持属性的浏览器仍可上报 requestStartresponseStartresponseEnd 等基础指标,但不能伪造 interim 时间。用能力字段标记浏览器是否支持该属性,并将新旧样本分开聚合;不要因为 API 缺失就阻断页面渲染。

7. 建立验证和治理

在 HTTP/2 或更高协议、同源和跨源、缓存命中与未命中、服务器发送与不发送 103 的环境中做对照。检查 interimWait >= 0、最终头时间不早于首个临时响应,并限制上报频率。指标解释要同时查看 LCP、预加载命中率和错误率,避免把网络时钟当作业务结果。

高质量示例回答

我会用 buffered PerformanceObserver 读取 firstInterimResponseStart,只在属性存在且非零时报告 1xx 等待时间。零值保留为不可判定状态,并结合同源性、Timing-Allow-Origin、缓存和浏览器能力做分层。是否采用 Early Hints 要由受控实验中的 LCP、资源命中率和错误率决定,而不是只看首个临时响应更早。

常见错误

  • firstInterimResponseStart 非零当成一定收到 103。
  • 把零值一律解释为服务器没有发 1xx。
  • 忽略跨源 Timing-Allow-Origin 导致的数据缺口。
  • responseStart 代替最终响应头时间,混淆 1xx 与最终响应。
  • 只在页面加载后调用 getEntriesByType,漏掉创建观察器前的条目。
  • 只看网络时序,不验证 LCP、预加载命中和错误率。

追问与回答

firstInterimResponseStart 能确认是 103 吗?

不能。它记录首个 1xx 响应字节,可能是 100 Continue 或其他临时响应。要确认 103,应结合服务器日志、受控请求和资源加载行为。

为什么跨源资源经常是零?

Resource Timing 会遮蔽跨源时序;没有匹配的 Timing-Allow-Origin 时,相关字段返回零。应修正响应策略或把样本归为不可观测,而不是补写估算值。

responseStartfinalResponseHeadersStart 有何区别?

存在临时响应时,responseStart 可能反映首个临时字节;finalResponseHeadersStart 用于最终响应头时间。评估服务器准备时间应优先使用后者。

旧浏览器如何降级?

做能力检测,继续采集通用的请求和响应时间,并用字段标记缺少 interim 指标。旧浏览器样本应与新 API 样本分开聚合。

如何证明 Early Hints 值得保留?

在相同网络、缓存和资源版本下做启用与禁用对照,比较 LCP、预加载命中率、最终头时间、资源完成时间和错误率;首个 1xx 更早只是中间证据。

公开来源

同类题目