Web Performance

Preload、prefetch 與 preconnect:各自何時真正有幫助

Resource hints 在符合真實瀏覽器瓶頸時很有用。盲目使用時,它們會增加優先順序雜訊,有時還會讓頁面變慢。

The Wux Webtools Team The Wux Webtools Team 9 分鐘閱讀 AI輔助,人類審核
A simplified browser loading waterfall showing early resource hints for a web page.
目錄
  1. Resource hints 不是魔法
  2. 瀏覽器已經做得很好的事
  3. Preload:用於目前頁面中發現得太晚的資源
  4. Preload 與 LCP images
  5. Prefetch:用於下一頁,而不是這一頁
  6. Preconnect:用於連到重要 origins 的昂貴連線
  7. DNS-prefetch:較輕量的表親
  8. 如何決定:實用 workflow
  9. 1. 找出瓶頸
  10. 2. 一次加入一個 hint
  11. 3. 檢查 priority side effects
  12. 4. 驗證 headers 與 caching
  13. 常見錯誤
  14. Preload 太多
  15. 對必要資源使用 prefetch
  16. Preconnect 到每個 third party
  17. 忘記 mobile conditions
  18. 簡單 decision table
  19. 冷靜原則

Resource hints 不是魔法

preloadprefetchpreconnect 經常被當成效能檢查清單。把幾個 tag 加到 <head>,重新跑 Lighthouse,感覺就安心了。但它們不是這樣運作的。

這些 hints 是給瀏覽器載入管線的指令。當你知道某些瀏覽器無法及早發現的資訊時,它們可以幫上忙。當你只是猜測、過度提高非關鍵工作的優先順序,或預先暖身使用者根本不需要的連線時,它們也可能造成傷害。

簡短版本如下:

  • 對目前頁面需要、但發現得太晚的資源使用 preload
  • 對可能的未來導覽資源使用 prefetch,不要用在目前頁面的必要資源。
  • 對連線建立確實造成延遲的重要第三方 origins 使用 preconnect

實際問題不是「哪個 hint 最快?」而是「瀏覽器正在等什麼,而這個 hint 能不能移除那段等待?」

瀏覽器已經做得很好的事

現代瀏覽器不是被動的檔案下載器。它們會解析 HTML、向前掃描資源、分配優先順序、重用連線、延後不可見的工作,並依網路狀況調整。

這表示 resource hints 應該有選擇地使用。如果 stylesheet、script、image 或 font 已經很早被發現,並且被給予正確的優先順序,加入 hint 可能沒有任何效果。更糟的是,它可能會與更重要的資源競爭。

加入 hints 之前,先看 DevTools 裡的 waterfall trace 或實驗室報告。如果你使用 Lighthouse,先從 diagnostics 開始,而不是分數;我們另有一篇指南說明如何不慌張地閱讀 Lighthouse report——但請注意正確 URL 有大小寫差異,因此如有需要,請從網站導覽使用連結文章。

真正的證據通常會出現在三個地方:

  1. 關鍵資源開始得很晚,因為瀏覽器發現得很晚。
  2. 連到重要 origin 的連線,在第一個 request 前花了明顯時間。
  3. 下一頁資源高度可預測,而且適合在閒置時間低成本抓取。

如果這些都不成立,hint 大概只是裝飾。

Preload:用於目前頁面中發現得太晚的資源

preload 告訴瀏覽器:「現在就抓這個資源,因為目前頁面會需要它。」

典型例子是 CSS 內引用的 web font。瀏覽器必須下載 HTML、發現 CSS、下載 CSS、解析 CSS、發現 font,然後才 request font。如果該 font 對首屏文字很重要,發現時間可能晚到造成 layout shifts 或延遲文字渲染。

preload 可以把該 request 提前:

<link rel='preload' href='/fonts/inter-var.woff2' as='font' type='font/woff2' crossorigin>

as attribute 很重要。它告訴瀏覽器這是什麼類型的資源,進而影響 priority、caching、content security policy 與 request headers。Fonts 通常也需要 crossorigin,即使是從同一個網站提供,因為 font fetching 使用 CORS mode。

好的 preload 候選包括:

  • 用於可見文字的主要 web font。
  • 作為 Largest Contentful Paint 元素、且無法及早發現的 hero image。
  • 間接載入的 critical CSS file。
  • 很早就需要、但藏在另一個 script 後面的 module 或 script。

不好的 preload 候選包括:

  • design system 裡的每一種 font weight。
  • 首屏以下的 images。
  • 初始渲染不需要的 scripts。
  • 瀏覽器已經在第一段 HTML chunk 中發現的資源。

Preload 很強大,因為它會影響目前頁面的優先順序。這也是它容易被誤用的原因。如果你 preload 五個大型 assets,你就不再是在幫助瀏覽器,而是在跟它爭論。

Fonts 是經典案例。Preload 一個主要 font file 可能有幫助。Preload 六種 weights 和 italics 通常會讓情況更糟。如果 fonts 是你的瓶頸,先修正 font set;我們的指南 web fonts are still the easiest performance win on most sites 更詳細說明了這項清理工作。

Preload 與 LCP images

當 LCP image 沒有出現在初始 HTML 中時,preload 可能有用。常見原因包括 CSS background images、client-rendered components,或出現得很晚的 responsive image logic。

但如果你的 hero image 已經以 <img> 放在 HTML 中,並具備合理的 srcsetsizes、dimensions,且沒有 lazy loading,瀏覽器大概能很快找到它。在這種情況下,依頁面而定,加入 fetchpriority='high' 可能比 preload 更合適。

一個好的測試方式:如果 image request 在 waterfall 中開始得很晚,並且成為 LCP element,就考慮 preload。如果它很早開始但下載很慢,問題在於 size、format、CDN behavior 或 server latency,而不是 discovery。關於 image format 的決策,請參考 when AVIF beats WebP and when it does not

Prefetch:用於下一頁,而不是這一頁

prefetch 告訴瀏覽器:「這個資源很快可能會需要,但現在不是必需。」

這個區別很重要。Prefetch 本來就是低優先順序。瀏覽器可能會在閒置時間抓取它並存起來供稍後使用。它也可能在連線不佳、data-saving modes 或記憶體壓力下略過它。

當使用者意圖強到足以讓下一個資源變得很可能時,才使用 prefetch。

好的 prefetch 候選包括:

  • 多頁 checkout 的下一步。
  • 使用者開始輸入 query 後的 search results,前提是下一個 route 可預測。
  • 使用者正在閱讀附近內容時,table of contents 連到的 documentation pages。
  • single-page app 中,使用者 hover 或 focus navigation item 之後的 route chunks。

不好的 prefetch 候選包括:

  • 你的整棵 navigation tree。
  • 大型 videos 或 image galleries。
  • 「以防萬一」的 third-party scripts。
  • 使用者很少接著造訪的頁面。

Prefetch 是節制會帶來回報的地方。抓了卻從未使用的資源並不是免費的。它會消耗 bandwidth、server capacity、energy,甚至可能消耗 user data。在行動網路上,speculative fetching 可能相當不友善。

對許多網站而言,最好的 prefetch strategy 是 intent-based。不要在 home page 一載入就 prefetch pricing page。等使用者打開 pricing menu、hover pricing link,或捲動到強烈預測導覽的 call-to-action 附近時再 prefetch。

也要記得瀏覽器行為會有所不同。有些瀏覽器對 prefetch 很保守;某些 privacy settings 會降低或停用 speculative loading。請把 prefetch 視為機會型改善,而不是正確性機制。

Preconnect:用於連到重要 origins 的昂貴連線

preconnect 告訴瀏覽器:「現在就開始建立到這個 origin 的連線。」

這可能包括 DNS lookup、TCP connection 與 TLS negotiation。對第三方 origins 而言,這個建立過程可能花上數百毫秒,尤其是在高延遲網路上。如果頁面很快需要來自該 origin 的 critical request,preconnect 可以讓後續 request 更快。

範例:

<link rel='preconnect' href='https://fonts.gstatic.com' crossorigin>

好的 preconnect 候選包括:

  • 用於 render-blocking text 的 font origin。
  • 初始互動期間需要的 critical API origin。
  • 提供首屏 assets 的 CDN origin。
  • 使用者動作後立即需要的 payments 或 identity provider。

不好的 preconnect 候選包括:

  • 對使用者不關鍵的 analytics 與 advertising endpoints。
  • 只在部分 sessions 使用的 origins。
  • 很長一串 third parties。
  • Same-origin resources,瀏覽器已經有連線,或很快就會開啟連線。

Preconnect 有持有成本。Open sockets 會消耗記憶體與網路資源。瀏覽器會關閉未使用的連線,但這不代表不必要的 preconnects 無害。

一個有用的規則:一個頁面最多只 preconnect 到一兩個高信心的 third-party origins。如果你想加入更多,你的 third-party architecture 可能比 hints 更需要檢視。

DNS-prefetch:較輕量的表親

你也可能看到 dns-prefetch

<link rel='dns-prefetch' href='https://example-cdn.com'>

這只會解析 domain name。它不會開啟 TCP 或 TLS connection。它比 preconnect 便宜,但幫助也比較小。

對於信心較低的 third-party origins,如果完整 preconnect 感覺太激進,DNS-prefetch 可以是合理選擇。實務上,如果某個 origin 很關鍵且很快一定會使用,優先使用 preconnect。如果只是可能會用,要嘛使用 DNS-prefetch,要嘛什麼都不做。

如何決定:實用 workflow

從測量開始,不要從 tags 開始。

1. 找出瓶頸

開啟 performance trace,尋找 late discovery。Font、hero image 或 script request 是否只在另一個檔案下載並解析後才開始?那就是 preload 候選。

如果 request 只在連到 third-party origin 的長時間 DNS/TCP/TLS setup 後才開始,那就是 preconnect 候選。

如果目前頁面沒問題,但下一次導覽可預測地很慢,prefetch 可能有幫助。

2. 一次加入一個 hint

Resource hints 會互相影響。加入一個、測試它,只有在 waterfall 改善且面向使用者的 metrics 沒有退步時才保留。

對 preload 而言,觀察被 hint 的資源是否真的很快被使用。Chrome 可能會在預載資源載入後短時間內未被使用時發出警告。請認真看待這個警告。

3. 檢查 priority side effects

preload 可能會把 bandwidth 從更重要的 CSS、JavaScript 或 images 拉走。preconnect 可能占用 connection slot。prefetch 可能增加 background traffic。

正確結果不是「被 hint 的檔案更早開始」。正確結果是「頁面對使用者而言有意義地變好」。盡可能查看 LCP、INP、CLS 與 real-user monitoring。

4. 驗證 headers 與 caching

Hints 可以放在 HTML 或 HTTP Link headers 中傳送。當 server 很早就知道頁面會需要什麼時,headers 很有用,但它們也較難隨手檢查。如果你在 debug production 中某個 hint 是否真的存在,raw headers 很重要;這正是 our guide to debugging redirects and HTTP headers 所涵蓋的情境。

Caching 也很重要。用不匹配的 credentials、錯誤的 as,或不同 URL parameters preload 資源,可能造成重複下載。這是善意 preload 變成效能 bug 最常見的方式之一。

常見錯誤

Preload 太多

如果一切都是 critical,就沒有任何東西是 critical。將 preload 限制在初始渲染或立即互動所需的資源。典型頁面應該有零到三個 preloads,而不是二十個。

對必要資源使用 prefetch

Prefetch 是低優先順序且可選的。不要把它用在目前頁面必需的 assets。如果頁面現在就需要它,考慮 preload 或正常的 HTML discovery。

Preconnect 到每個 third party

第三方繁重的頁面常有十個或更多 external origins。對所有 origins preconnect 會製造雜訊。只挑一兩個既 critical 又可預測會使用的。

忘記 mobile conditions

Resource hints 在較慢連線上最有價值,但也最危險。在快速 desktop connection 上浪費一次 prefetch 只是微小誤差。在受限的 mobile plan 上,這是糟糕的取捨。

簡單 decision table

| Situation | Best hint | Why | |---|---:|---| | 透過 CSS 發現的 critical font | preload | 目前頁面需要它,discovery 很晚 | | 藏在 CSS 或 client rendering 後面的 hero image | preload | 如果 image 開始得晚,可改善 LCP | | 使用者意圖後的可能下一個 route | prefetch | 不阻塞目前頁面,又能幫助未來導覽 | | Critical third-party font/API origin | preconnect | 從 critical path 移除 connection setup | | 可能但不確定的 third-party origin | dns-prefetch 或無 | 成本較低,信心也較低 | | 首屏以下的 image | 無 | 讓 lazy loading 與瀏覽器優先順序發揮作用 |

冷靜原則

Resource hints 在無聊且具體時效果最好。一個 font。一張 LCP image。一個重要 third-party origin。一個在意圖後很可能前往的下一個 route。

當它們被當成樂觀猜測時效果很差:也許使用者會需要這個,也許瀏覽器應該抓那個,也許更多 hints 代表更快。

瀏覽器已經積極最佳化。你的工作不是微管理每一個 request。你的工作是在少數瀏覽器於正確時刻缺乏資訊的情況下加以修正。

常見問題

我應該 preload 所有 fonts 嗎?
不應該。只 preload 頁面早期可見文字所需的 font files。Preload 每一種 weight 和 style 通常會浪費 bandwidth,並可能延遲更重要的資源。
對每個 internal link 使用 prefetch 安全嗎?
通常不安全。它可能產生不必要的 background traffic,並浪費 user data。請優先使用 intent-based prefetching,例如 hover、focus、開啟 menu,或出現可預測的下一步之後。
preconnect 和 dns-prefetch 有什麼不同?
Preconnect 會對某個 origin 執行 DNS、TCP 與 TLS setup。DNS-prefetch 只解析 domain name。Preconnect 更強但成本更高,因此應該在更有信心時使用。
Resource hints 可以改善 Core Web Vitals 嗎?
可以,尤其是 LCP;當它們修正關鍵資源的 late discovery 或 connection setup 時特別有效。如果真正問題是 assets 過大、server response 緩慢、render-blocking code 或 caching 不佳,它們就不會有幫助。
Resource hints 應該加在 HTML 還是 HTTP headers?
兩者都可以。對 page-specific hints 而言,HTML 較容易推理。當 server 在 HTML 解析前就知道 critical resources 時,HTTP Link headers 可能有用,但需要仔細測試以避免重複或過期的 hints。

來源與進一步閱讀

  1. MDN: rel=preload
  2. MDN: Resource hints
  3. web.dev: Preconnect and DNS-prefetch
  4. W3C: Resource Hints
關於作者
The Wux Webtools Team

最後更新:

繼續閱讀