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

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

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

本指南將說明如何透過 <link 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 區塊: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 受到新式瀏覽器廣泛支援,可有效改善許多使用者的瀏覽體驗。這項技術需要載入可能不會用到的額外位元組,因此使用時請留意;請只在必要時進行,而且最好只使用快速網路。