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

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

研究顯示,載入時間越短,轉換率就越高,使用者體驗也越好。如果您瞭解使用者在網站上的瀏覽路徑,以及他們接下來可能會造訪哪些網頁,就可以提前下載這些網頁的資源,進而縮短日後的瀏覽載入時間。

本指南將說明如何透過 <link rel=prefetch> 實現這項功能。<link 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 可讓預先擷取的指令碼更快處理,不必等到瀏覽期間網路先擷取該指令碼。這可能會影響網頁的 Interaction to Next Paint (INP)。如果標記是透過 JavaScript 在用戶端轉譯,則可透過減少資源載入延遲來改善 LCP,並更快完成包含網頁 LCP 元素的用戶端標記轉譯作業。
  • 預先擷取目前網頁未使用的網路字型,可以消除版面配置偏移。在使用 font-display: swap; 的情況下,系統會移除字型交換期間,進而加快文字轉譯速度,並消除版面配置位移。如果日後的網頁使用預先載入的字型,且該網頁的 LCP 元素是使用網路字型的文字區塊,則該元素的 LCP 也會變快。

預先擷取隨選 JavaScript 區塊

程式碼分割 JavaScript 套件可讓您一開始只載入應用程式的部分內容,並延後載入其餘內容。如果您使用這項技術,可以將預先載入套用至不立即必要,但可能很快就會要求的路徑或元件。

舉例來說,如果網頁包含一個按鈕,而該按鈕會開啟含有表情符號挑選器的對話方塊,您可以將該按鈕分為三個 JavaScript 區塊:home、dialog 和 picker。您可以先載入首頁和對話方塊,再視需要載入選擇器。您可以使用 webpack 等工具,指示瀏覽器預先擷取這些隨選區塊。

如何實作 rel=prefetch

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

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

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

您也可以透過 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

如果使用者使用速度緩慢的網路,或是已啟用 Save-Data,quicklink 和 Guess.js 都會使用 Network Information API 避免預先載入。

預先擷取的秘密

資源提示並非強制執行的操作說明,瀏覽器會自行決定是否執行,以及執行的時間。

您可以在同一頁面中多次使用預先載入功能。瀏覽器會在閒置時,將所有提示排入佇列,並要求每項資源。在 Chrome 中,如果預先載入尚未完成載入,且使用者前往預先載入資源的目的網頁,瀏覽器就會將載入中的資源視為導覽 (其他瀏覽器供應商可能會以不同的方式實作這項功能)。

預先擷取作業的優先順序為 'Lowest',因此預先擷取的資源不會與目前網頁所需的資源爭奪頻寬。

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

結論

使用 prefetch 可大幅縮短日後導覽的載入時間,甚至讓網頁看起來像是即時載入。prefetch 在現今瀏覽器中廣泛支援,因此是改善許多使用者瀏覽體驗的實用技巧。這項技術需要載入可能不會使用的額外位元組,因此請謹慎使用;請只在必要時使用,並且最好只在快速網路上使用。