如何用 firstInterimResponseStart 衡量 Early Hints 的實際收益?
題目與背景
瀏覽器開始支援 PerformanceResourceTiming.firstInterimResponseStart,它記錄收到首個暫時 1xx 回應位元組的時間。請實作觀測邏輯,評估 103 Early Hints 是否縮短資源準備時間,並處理不支援、跨來源和快取場景。
面試官考察什麼
- 是否理解
requestStart、firstInterimResponseStart和最終回應標頭時間的關係。 - 是否知道 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. 寫出觀測器
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. 設計相容降級
不支援屬性的瀏覽器仍可上報 requestStart、responseStart 和 responseEnd 等基礎指標,但不能偽造 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 時,相關欄位回傳零。應修正回應策略或把樣本歸為不可觀測,而不是補寫估算值。
responseStart 和 finalResponseHeadersStart 有何區別?
存在暫時回應時,responseStart 可能反映首個暫時位元組;finalResponseHeadersStart 用於最終回應標頭時間。評估伺服器準備時間應優先使用後者。
舊瀏覽器如何降級?
做能力檢測,繼續採集通用的請求和回應時間,並用欄位標記缺少 interim 指標。舊瀏覽器樣本應與新 API 樣本分開彙總。
如何證明 Early Hints 值得保留?
在相同網路、快取和資源版本下做啟用與停用對照,比較 LCP、預載命中率、最終標頭時間、資源完成時間和錯誤率;首個 1xx 較早只是中間證據。