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

瞭解 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 能更快完成預先擷取的指令碼處理作業。這會影響回應速度指標,例如首次輸入延遲時間 (FID)下次顯示所需時間 (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) });
});

與其等待「submit」事件載入此功能,您可以預先擷取這項資源,以便在使用者提交表單時,提高資源在快取中的機率。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 偵測連結進入可視區域的時機,並在閒置期間預先擷取已連結的資源。額外好處:Quicklink 的體重不到 1 KB!
  • Guess.js 會根據數據分析報表建構預測模型,以便透過智慧預先擷取使用者可能需要的內容,進行智慧預先擷取。

快速連結和 Guess.js 都會使用 Network Information API,在使用者網路速度緩慢或已啟用 Save-Data 時避免預先擷取。

後端預先擷取

資源提示並非強制指示,瀏覽器可自行判斷是否執行以及執行的時間。

您可以在同一個網頁中多次使用預先擷取功能。瀏覽器會在資源閒置時,將所有提示和要求排入佇列。在 Chrome 中,如果預先擷取功能尚未完成載入,且使用者前往預定的預先擷取資源,瀏覽器就會擷取傳輸中負載 (其他瀏覽器供應商可能採用不同的導入方式)。

預先擷取作業會以「最低」的優先順序進行,因此預先擷取的資源不會與目前網頁所需的資源競爭。

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

結語

使用 prefetch 可大幅縮短日後瀏覽的過程,甚至可以讓網頁立即載入。prefetch 支援許多新式瀏覽器,因此這項技術十分適合用於改善許多使用者的導覽體驗。這項技術需要載入額外位元組,因此使用時請特別留意,最好只在必要時執行,而且最好只在網路速度較快的網路環境中執行。