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

瞭解 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 可讓預先擷取的指令碼更快處理,不必等到瀏覽期間網路先擷取該指令碼。這可能會影響網頁的 Interaction to Next Paint (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 屬性可協助瀏覽器設定正確的標頭,並判斷資源是否已存在快取中。這個屬性的值範例包括: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 的程式庫,實作聰明的預先擷取功能:

  • quicklink 會使用 Intersection Observer API 偵測連結何時進入檢視區,並在閒置時間期間預先載入已連結的資源。額外資訊:快速連結的大小不到 1 KB!
  • Guess.js 使用數據分析報表建立預測模型,能夠以智慧方式預先擷取使用者可能需要的內容。

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

預先擷取的秘密

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

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

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

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

結論

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