使用 Early Hints 伺服器思考時間,加快網頁載入速度

瞭解伺服器如何向瀏覽器傳送關於重要子資源的提示。

什麼是早期提示?

網站日趨複雜,因此,伺服器需要執行非簡單的工作 (例如存取資料庫,或 CDN 存取來源伺服器),以便產生要求網頁的 HTML,這並非不尋常。不過,這段「伺服器思考時間」會導致瀏覽器在開始轉譯網頁前,產生額外的延遲時間。事實上,只要伺服器需要準備回應,連線就會處於閒置狀態。

這張圖片顯示,在載入網頁和其他資源之間,伺服器的思考時間差距為 200 毫秒。
不使用早期提示:伺服器會封鎖所有內容,以便決定如何回應主要資源。

早期提示是一種 HTTP 狀態碼 (103 Early Hints),用於在最終回應之前傳送初步 HTTP 回應。這樣一來,伺服器在忙於產生主要資源時,就能向瀏覽器傳送關於重要子資源 (例如網頁的樣式表單、重要 JavaScript) 或網頁可能會使用的來源的提示。瀏覽器可以使用這些提示暖機連線,並在等待主要資源時要求子資源。換句話說,早期提示可協助瀏覽器提前執行部分工作,充分利用「伺服器思考時間」,進而加快網頁載入速度。

這張圖片顯示 Early Hints 如何讓網頁傳送部分回應。
使用早期提示:伺服器可在決定最終回應時,提供含有資源提示的部分回應

在某些情況下,最大內容繪製時間的效能改善幅度可能會從數百毫秒提升至 1 秒,如 ShopifyCloudflare 的觀察結果所示。請參閱下方比較圖表,瞭解改善前後的差異:

兩個網站的比較。
使用 WebPageTest 在測試網站上進行的早期提示前後比較 (Moto G4 - DSL)

如何使用早期提示

要充分運用早期提示,第一步就是找出最熱門的到達網頁,也就是使用者造訪網站時通常會先看到的網頁。這可能是首頁,或是熱門產品資訊頁面 (如果有許多使用者是來自其他網站)。這些進入點比其他網頁更重要,是因為使用者在網站中瀏覽時,早期提示的效用會降低 (也就是說,瀏覽器在第二或第三次後續導覽時,更有可能擁有所需的所有子資源)。建立良好的第一印象也是不錯的做法!

有了這個優先順序的到達網頁清單後,下一步就是找出哪些來源或子資源適合用於 preconnectpreload 提示。通常,這些來源和子資源會對最大內容繪製首次顯示內容所需時間等主要使用者指標貢獻最多。具體來說,請找出會造成轉譯阻斷的子資源,例如同步 JavaScript、樣式表,甚至是網路字型。同樣地,請找出代管子資源的來源,這些子資源對主要使用者指標的貢獻度很高。

另外請注意,如果主要資源已使用 preconnectpreload,您可以將這些來源或資源列為提早提示的候選項目。詳情請參閱如何改善 LCP。不過,直接將 HTML 中的 preconnectpreload 指令複製到 Early Hints 可能不是最佳做法

在 HTML 中使用這些元素時,您通常會想 preconnectpreload 預先載入掃描器不會在 HTML 中發現的資源,例如字型或背景圖片,因為這些資源會在較晚的時間才會被發現。對於早期提示,您不會有 HTML,因此建議您改為 preconnect 至重要網域,或 preload重要資源,這些資源可能會在 HTML 中提早發現,例如預先載入 main.cssapp.js。此外,並非所有瀏覽器都支援早期提示的 preload,請參閱瀏覽器支援

第二步則是盡量降低在資源或來源上使用早期提示的風險,這些資源或來源可能已淘汰,或不再由主要資源使用。舉例來說,經常更新且有版本的資源 (例如 example.com/css/main.fa231e9c.css) 可能不是最佳選擇。請注意,這項疑慮並非僅限於早期提示,而是適用於任何可能出現的 preloadpreconnect。這類細節最適合透過自動化或模板處理 (例如,手動程序較有可能導致 preload 與使用該資源的實際 HTML 標記之間的雜湊或版本網址不相符)。

舉例來說,請思考以下流程:

GET /main.html
Host: example.com
User-Agent: [....] Chrome/103.0.0.0 [...]

伺服器會預測需要 main.abcd100.css,並建議使用 Early Hints 預先載入:

103 Early Hints
Link: </main.abcd100.css>; rel=preload; as=style
[...]

幾秒後,系統就會放送包含連結 CSS 的網頁。很抱歉,這個 CSS 資源經常更新,而且主資源已比預測的 CSS 資源 (abcd100) 提前五個版本 (abcd105)。

200 OK
[...]
<HTML>
<head>
   <title>Example</title>
   <link rel="stylesheet" href="/main.abcd105.css">

一般來說,請選擇相當穩定的資源和來源,且與主要資源的結果無關。如有需要,您可以考慮將主要資源分成兩部分:一個穩定的部分可搭配 Early Hints 使用,另一個較具動態性的部分則可在瀏覽器收到主要資源後擷取:

<HTML>
<head>
   <title>Example</title>
   <link rel="stylesheet" href="/main.css">
   <link rel="stylesheet" href="/experimental.3eab3290.css">

最後,在伺服器端尋找已知支援早期提示的瀏覽器傳送的主要資源要求,並立即傳回 103 早期提示。在 103 回應中加入相關的預先連線和預先載入提示。主要資源準備就緒後,請回覆一般回應 (例如,成功時傳回 200 OK)。為了確保向後相容性,建議您在最終回應中加入 Link HTTP 標頭,甚至可以加入在產生主要資源時發現的重要資源 (例如,如果您遵循「分割成兩個」的建議,則為主要資源的動態部分)。如下所示:

GET /main.html
Host: example.com
User-Agent: [....] Chrome/103.0.0.0 [...]
103 Early Hints
Link: <https://fonts.google.com>; rel=preconnect
Link: </main.css>; rel=preload; as=style
Link: </common.js>; rel=preload; as=script

幾分鐘後:

200 OK
Content-Length: 7531
Content-Type: text/html; charset=UTF-8
Content-encoding: br
Link: <https://fonts.google.com>; rel=preconnect
Link: </main.css>; rel=preload; as=style
Link: </common.js>; rel=preload; as=script
Link: </experimental.3eab3290.css>; rel=preload; as=style
<HTML>
<head>
   <title>Example</title>
   <link rel="stylesheet" href="/main.css">
   <link rel="stylesheet" href="/experimental.3eab3290.css">
   <script src="/common.js"></script>
   <link rel="preconnect" href="https://fonts.googleapis.com">

瀏覽器支援

雖然所有主要瀏覽器都支援 103 Early Hints,但可透過 Early Hints 傳送的指令會因瀏覽器而異:

Preconnect 支援:

瀏覽器支援

  • Chrome:103。
  • Edge:103。
  • Firefox:120。
  • Safari:17。

預先載入支援:

瀏覽器支援

  • Chrome:103。
  • Edge:103。
  • Firefox:123。
  • Safari:不支援。

Chrome 開發人員工具也支援 103 Early Hints,您可以在文件資源中看到 Link 標頭:

網路面板顯示早期提示標頭
Chrome 開發人員工具中顯示的「Early Hints」Link標頭。

請注意,如要使用早期提示資源,請勿在開發人員工具中勾選 Disable cache,因為早期提示會使用瀏覽器快取。對於預先載入的資源,啟動工具會顯示為 early-hints大小則為 (Disk cache)

顯示早期提示啟動工具的網路面板
早期提示資源具有 early-hints 啟動程序,並從磁碟快取載入。

這也需要 HTTPS 測試的受信任憑證。

Firefox (截至第 126 版) 在 DevTools 中沒有明確的 103 Early Hints 支援,但使用 Early Hints 載入的資源不會顯示 HTTP 標頭資訊,這也是透過 Early Hints 載入資源的一種指標。

伺服器支援

以下簡要說明熱門開放原始碼軟體 HTTP 伺服器軟體支援早期提示的程度:

以更簡單的方式啟用提示功能

如果您使用的是下列任一 CDN 或平台,可能就不需要手動導入提示。請參閱解決方案供應商的線上說明文件,瞭解該供應商是否支援 Early Hints,或參閱以下不完整清單:

如何避免不支援早期提示的用戶端發生問題

100 範圍內的資訊性 HTTP 回應是 HTTP 標準的一部分,但某些較舊的用戶端或機器人可能無法處理這些回應,因為在 103 早期提示推出前,這些回應很少用於一般網頁瀏覽。

只有在回應傳送 sec-fetch-mode: navigate HTTP 要求標頭的用戶端時,才會傳送 103 早期提示,這樣才能確保這些提示只會傳送給瞭解如何等待後續回應的新版用戶端。此外,由於 Early Hints 僅支援導覽要求 (請參閱目前的限制),因此這項功能還有另一項優點,可避免在其他要求中不必要地傳送這些資訊。

此外,建議您只透過 HTTP/2 或 HTTP/3 連線傳送早期提示,且大多數瀏覽器只會透過這些通訊協定接受早期提示。

進階模式

如果您已將早期提示完全套用至主要到達網頁,並想尋找更多商機,不妨試試下列進階模式。

如果訪客在典型使用者歷程中提出第 n 次網頁要求,您可能要將 Early Hints 回應調整為網頁中較低層級和較深層的內容,也就是在較低優先順序的資源上使用 Early Hints。這聽起來可能違反直覺,因為我們建議您著重於高優先順序的轉譯阻斷子資源或來源。不過,當訪客瀏覽一段時間後,瀏覽器很可能已經取得所有重要資源。從那時起,您可能就該將注意力轉移到優先順序較低的資源。舉例來說,這可能表示使用 Early Hints 載入產品圖片,或是只需在較不常見的使用者互動中使用的額外 JS/CSS。

目前限制

以下是 Chrome 中實作的早期提示功能限制:

  • 僅適用於導覽要求 (也就是頂層文件的主要資源)。
  • 僅支援 preconnectpreload (也就是不支援 prefetch)。
  • 如果在最終回應中,早期提示後接著跨來源重新導向,Chrome 就會捨棄使用早期提示取得的資源和連線。
  • 使用 Early Hints 預先載入的資源會儲存在 HTTP 快取中,並在稍後由網頁擷取。因此,只有可快取的資源才能使用 Early Hints 預先載入,否則資源會重複擷取 (一次由 Early Hints 擷取,一次由文件擷取)。在 Chrome 中,如果 HTTPS 憑證不受信任,系統會停用 HTTP 快取 (即使您繼續載入頁面也是如此)。
  • 不支援使用 HTTP <link> 標頭預先載入回應式圖片 (使用 imagesrcsetimagesizesmedia),因為視區會在建立文件後才定義。這表示 103 早期提示無法用於預先載入回應式圖片,且在用於此用途時,可能會載入錯誤的圖片。請參閱這篇討論文章,瞭解如何更妥善地處理這類提案。

其他瀏覽器也有類似的限制,如先前所述,部分瀏覽器會進一步將 103 早期提示限制為僅限 preconnect

後續步驟

視社群的興趣而定,我們可能會在實作早期提示時加入下列功能:

  • 針對無法快取的資源,使用記憶體快取而非 HTTP 快取的早期提示。
  • 在子資源要求中傳送的早期提示。
  • 在 iframe 主要資源要求中傳送的早期提示。
  • 支援在 Early Hints 中預先載入。

歡迎提供意見,告訴我們應優先處理哪些部分,以及如何進一步改善早期提示。

與 H2/Push 的關係

如果您熟悉已淘汰的 HTTP2/Push 功能,可能會想知道早期提示的差異。雖然早期提示需要瀏覽器進行一次往返作業,才能開始擷取重要子資源,但在使用 HTTP2/Push 時,伺服器可以開始推送子資源,並附帶回應。雖然這聽起來很棒,但這會導致一個重要的結構性缺點:在 HTTP2/Push 中,很難避免推送瀏覽器已擁有的子資源。這種「過度推送」效應會導致網路頻寬使用效率降低,大幅降低效能優勢。總體而言,Chrome 資料顯示,HTTP2/Push 對整個網站的效能而言,實際上是淨負面。

相較之下,Early Hints 在實際上更有效率,因為它結合了傳送初步回應的功能,以及讓瀏覽器負責擷取或連線至實際需要的內容的提示。雖然早期提示無法涵蓋 HTTP2/Push 理論上可處理的所有用途,但我們認為早期提示是加快導覽速度的更實用解決方案。

縮圖圖片由 Pierre Bamin 提供。