預先擷取資源,加快日後瀏覽的速度

瞭解 rel=prefetch 資源提示及使用方法。

研究顯示,載入時間越短,轉換率就會越高及改善使用者體驗。如果您知道使用者瀏覽網站的方式,以及他們接下來可能會造訪哪些網頁,就可以預先下載這些網頁的資源,縮短日後瀏覽時的載入時間。

本指南說明如何使用 <link rel=prefetch> 完成這項作業。這項資源提示可讓您以簡單又有效率的方式導入預先擷取。

使用 rel=prefetch 改善導航品質

在網頁中加入 <link rel=prefetch> 會指示瀏覽器下載使用者日後可能需要的整個網頁或部分資源 (例如指令碼或 CSS 檔案):

<link rel="prefetch" href="/articles/" as="document">

顯示連結預先擷取功能的運作方式圖表。

prefetch 提示會為不需立即使用的資源耗用額外位元組,因此必須謹慎採用這項技術。除非您確定使用者有需要的資源,否則請勿預先擷取資源。當使用者連線速度緩慢時,建議不要預先擷取。您可以使用 Network Information API 進行偵測。

您可以透過不同的方式決定要預先擷取的連結。其中最簡單的連結就是預先擷取目前網頁上的第一個連結或前幾個連結。另有許多程式庫使用更複雜的做法,詳情請參閱本文後續章節。

用途

預先擷取後續網頁

如果後續的網頁可以預測,就預先擷取 HTML 文件,這樣使用者點擊連結時,系統就會立即載入網頁。

舉例來說,您可以在產品資訊頁面中,預先擷取清單中最熱銷產品的網頁。有時候,下一個瀏覽方式更容易預測:在購物車頁面上,使用者造訪結帳頁面的可能性通常較高,因此適合預先擷取。

雖然預先擷取資源會耗用額外頻寬,但這麼做能改善大部分的效能指標。「第一個位元組的時間」(TTFB) 通常會大幅降低,因為文件要求會導致快取命中。由於 TTFB 會較低,因此後續的時間指標通常也會較低,包括最大內容繪製 (LCP)首次內容繪製 (FCP)

預先擷取靜態資產

系統可預測使用者後續造訪的部分,然後預先擷取靜態素材資源,例如指令碼或樣式表。當這些資源在多個網頁上共用時,這項功能就特別實用。

舉例來說,Netflix 會善用使用者在未登入網頁停留的時間,預先擷取 React (使用者登入後即可使用)。因此,他們將互動間隔時間縮短了 30%

預先擷取靜態資產對效能指標的影響,取決於預先擷取的資源:

  • 預先擷取圖片可能會大幅縮短 LCP 圖片元素的 LCP 時間。
  • 預先擷取樣式表可以改善 FCP 和 LCP,因為下載樣式表的網路時間會因此被省略。因為樣式表會妨礙顯示,所以在預先擷取時可以減少 LCP。如果後續網頁的 LCP 元素是透過 background-image 屬性要求的 CSS 背景圖片,系統也會預先擷取圖片,做為預先擷取的樣式表的相依資源。
  • 預先擷取 JavaScript 會比預先擷取的指令碼更快地進行處理,比網路在瀏覽時需要擷取指令碼的速度更快。這可能會影響網頁的「與下一個顯示的內容互動 (INP)」。如果標記是透過 JavaScript 在用戶端轉譯,可縮短資源載入延遲時間,進而在用戶端轉譯包含網頁 LCP 元素的標記,從而改善 LCP。
  • 預先擷取目前網頁尚未使用的網路字型,可以避免版面配置位移。如果使用 font-display: swap;,系統會排除字型的交換期,從而加快文字算繪速度並消除版面配置位移。如果日後的網頁使用預先擷取的字型,且網頁的 LCP 元素是使用網頁字型的文字區塊,則該元素的 LCP 也會加快。

預先擷取隨選 JavaScript 區塊

編寫程式碼分割:您可以利用 JavaScript 套件,一開始只載入應用程式的某些部分並延遲載入其餘部分。假如您使用這項技巧,則可將預先擷取功能套用至非立即必要但可能很快就會要求的路徑或元件。

舉例來說,如果您的網頁上有一個按鈕可開啟含有表情符號挑選器的對話方塊,您可以將該按鈕分成三個 JavaScript 區塊,分別是主畫面、對話方塊和挑選器。首頁和對話方塊可先載入,同時視需要載入挑選器。Webpack 等工具可指示瀏覽器預先擷取這些隨選區塊。

如何導入 rel=prefetch

實作 prefetch 最簡單的方法,就是在文件的 <head> 中新增 <link> 標記:

<head>
  ...
  <link rel="prefetch" href="/articles/" as="document">
  ...
</head>

as 屬性可協助瀏覽器設定正確的標頭,並判斷資源是否已在快取中。這個屬性的範例值包括:documentscriptstylefontimageother

您也可以透過 Link HTTP 標頭啟動預先擷取:

Link: </css/style.css>; rel=prefetch

在 HTTP 標頭中指定預先擷取提示的一大優點,就是瀏覽器無須剖析文件即可找出資源提示,在某些情況下,這項功能還可帶來小幅改善。

使用 Webpack 神奇註解預先擷取 JavaScript 模組

webpack 可讓您預先擷取出合理使用者很快就會造訪或使用中的路徑或功能指令碼。

下列程式碼片段會延遲載入 lodash 程式庫中的排序功能,以便將透過表單提交的一組數字排序:

form.addEventListener("submit", e => {
  e.preventDefault()
  import('lodash.sortby')
    .then(module => module.default)
    .then(sortInput())
    .catch(err => { alert(err) });
});

與其等著「提交」事件載入該功能,您可以預先擷取這項資源,進而提高使用者提交表單時,快取出現的機率。Webpack 允許在 import() 中使用魔術註解

form.addEventListener("submit", e => {
   e.preventDefault()
   import(/* webpackPrefetch: true */ 'lodash.sortby')
         .then(module => module.default)
         .then(sortInput())
         .catch(err => { alert(err) });
});

這會指示 Webpack 將 <link rel="prefetch"> 標記插入 HTML 文件中:

<link rel="prefetch" as="script" href="1.bundle.js">

預先擷取隨選區塊的效能優勢略有不同,但一般來說,預期對於依賴隨選區塊的互動可以更快獲得回應,因為這些區塊會立即提供使用。視互動的性質而定,這對於網頁的 INP 有影響。

一般而言,預先擷取功能也會將整體資源優先順序列入考量。預先擷取資源時,系統會以最低的優先順序處理。因此,任何預先擷取的資源都不會佔用目前頁面所需資源的頻寬。

您也可以透過使用 prefetch 的程式庫,實作聰明的預先擷取功能:

  • Fastlink 會使用 Intersection Observer API,偵測連結進入可視區域的時機,並在閒置期間預先擷取連結資源。額外優勢:Quicklink 的重量不到 1 KB!
  • Guess.js 使用數據分析報表建立預測模型,能夠以智慧方式預先擷取使用者可能需要的內容。

快速連結和 Guess.js 都會使用 Network Information API,當使用者的網路連線速度緩慢或是開啟了 Save-Data 時,即不會預先擷取內容。

內部預先擷取

資源提示並非強制指示,可由瀏覽器決定是否執行,以及執行的時機和時間。

您可以在相同網頁中多次使用預先擷取。瀏覽器會將所有提示排入佇列,並在每項資源處於「閒置」狀態時提出要求。使用 Chrome 時,如果預先擷取尚未完成載入,使用者也開啟目的地的預先擷取資源,瀏覽器就會選取傳輸中載入,做為瀏覽器導覽 (其他瀏覽器廠商可能會採用不同的實作方式)。

在 [最低] 動作進行預先擷取的時間:優先順序,因此預先擷取的資源不會與目前頁面所需要的資源競爭頻寬。

預先擷取的檔案會儲存在 HTTP 快取記憶體快取中 (視資源是否可快取而定),時間長度會因瀏覽器而異。舉例來說,Chrome 資源會將大約保留五分鐘,之後便會對資源套用一般的 Cache-Control 規則。

結論

使用 prefetch 可大幅縮短日後瀏覽時的載入時間,甚至可立即載入網頁。prefetch 受到新式瀏覽器廣泛支援,可有效改善許多使用者的瀏覽體驗。這項技巧需要載入可能未使用的額外位元組,因此使用時請務必留意並只在必要時進行,最好使用快速網路。