程式碼研究室:預先載入重要資產,藉此提升載入速度

在本程式碼研究室中,系統會預先載入及預先擷取一些資源,藉此提升以下網頁的效能:

應用程式螢幕截圖

測量

請先評估網站成效,再加入任何最佳化項目。

  • 如要預覽網站,請按下「查看應用程式」,然後按下「全螢幕」圖示 全螢幕

在 Glitch 的即時版本中執行 Lighthouse 效能稽核 (依序點選「Lighthouse」>「選項」>「效能」)。另請參閱「使用 Lighthouse 探索效能商機」。

Lighthouse 針對延遲擷取的資源,顯示下列失敗稽核資訊:

Lighthouse:預先載入金鑰要求稽核
  • 按下 `Control+Shift+J 鍵 (在 Mac 上為 Command+Option+J 鍵) 開啟開發人員工具。
  • 按一下 [網路] 分頁標籤。
顯示最近發現資源的網路面板

不會由放置於 HTML 文件的連結元素 (<link>) 擷取 main.css 檔案,但獨立的 JavaScript 檔案 fetch-css.js 會在 window.onLoad 事件之後,將 Link 元素附加至 DOM。這表示只有在瀏覽器完成剖析和執行 JS 檔案「之後」,系統才會擷取檔案。同樣地,在 CSS 檔案下載完畢之後,系統才會擷取 main.css 中指定的網路字型 (K2D.woff2)。

重要要求鏈代表瀏覽器優先順序和擷取的資源順序。這個網頁目前看起來會像這樣:

├─┬ / (initial HTML file)
  └── fetch-css.js
    └── main.css
      └── K2D.woff2

由於 CSS 檔案位於要求鏈的第三層,因此 Lighthouse 已將該檔案視為延遲發現的資源。

預先載入重要資源

main.css 檔案是頁面在載入後立即需要用到的重要素材資源。如果應用程式較晚會擷取這類重要檔案,請使用連結預先載入標記,在文件標題中加入 Link 元素,通知瀏覽器應提前下載。

為這個應用程式新增預先載入標記:

<head>
  <!-- ... -->
  <link rel="preload" href="main.css" as="style">
</head>

as 屬性用來識別正在擷取的資源類型,as="style" 則用於預先載入樣式表檔案。

重新載入應用程式,並查看開發人員工具中的「網路」面板。

顯示預先載入資源的網路面板

請注意,瀏覽器如何在負責擷取 CSS 檔案之前擷取 CSS 檔案,直到剖析完成。預先載入時,瀏覽器會假設這是對網頁的重要項目,因此會預先擷取資源。

如未正確使用,預先載入功能可能會對未使用的資源發出不必要的要求,進而影響效能。在這個應用程式中,details.css 是另一個位於專案根目錄的 CSS 檔案,但用於獨立的 /details route。如要舉例說明如何正確使用預先載入功能,請一併為這項資源新增預先載入提示。

<head>
  <!-- ... -->
  <link rel="preload" href="main.css" as="style">
  <link rel="preload" href="details.css" as="style">
</head>

重新載入應用程式,並查看「Network」面板。即使網頁並未使用 details.css,系統仍會發出擷取要求。

含有非必要預先載入的網路面板

如果某個預先載入的資源沒有在載入後的幾秒內使用,Chrome 會在「Console」面板中顯示警告。

控制台預先載入警告

並以此警告做為指標,找出您的網頁是否沒有立即使用的任何預先載入資源。您現在可以移除這個頁面不必要的預先載入連結。

<head>
  <!-- ... -->
  <link rel="preload" href="main.css" as="style">
  <link rel="preload" href="details.css" as="style">
</head>

如需可擷取的所有資源類型清單,以及應用於 as 屬性的正確值,請參閱預先載入的 MDN 文章

預先擷取未來資源

「預先擷取」是其他瀏覽器提示,可用於為不同導覽路徑使用的資產發出要求,但優先順序低於目前頁面所需的其他重要資產。

在這個網站中,按一下圖片即可前往獨立的 details/ 路徑。

詳細資料路徑

獨立的 CSS 檔案 details.css 包含這個簡單頁面所需的所有樣式。將連結元素新增至 index.html,即可預先擷取這項資源。

<head>
  <!-- ... -->
  <link rel="prefetch" href="details.css">
</head>

如想瞭解這樣做如何觸發檔案要求,請開啟開發人員工具中的「Network」面板,然後取消勾選「Disable cache」選項。

停用 Chrome 開發人員工具的快取

重新載入應用程式,您會發現在擷取所有其他檔案後,系統會如何針對 details.css 發出極低的優先順序要求。

含有預先擷取資源的網路面板

開啟開發人員工具後,按一下網站上的圖片即可前往 details 頁面。 由於 details.html 中使用連結元素來擷取 details.css,因此系統會如預期對資源發出要求。

詳細資料頁面網路要求

在開發人員工具中按一下 details.css 網路要求,即可查看詳細資料。您會看到檔案已經從瀏覽器的磁碟快取中擷取。

從磁碟快取中擷取詳細資料要求

預先擷取功能會利用瀏覽器閒置時間,針對不同網頁所需的資源及早發出要求。這可讓瀏覽器更快快取素材資源,並視需要從快取提供,加快日後的瀏覽要求。

使用 Webpack 預先載入及預先擷取

透過程式碼分割來減少 JavaScript 酬載後,探索如何使用動態匯入將一個組合分割成多個區塊。這個範例使用簡單的應用程式,在提交表單時會從 Lodash 動態匯入模組。

示範程式碼分割功能的 Magic Sorter 應用程式

您可以按這裡存取這個應用程式的 Glitch。

以下程式碼區塊位於 src/index.js, 中,負責在使用者點選按鈕時動態匯入方法。

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

分割套件可減少初始大小,藉此縮短網頁載入時間。4.6.0 版的 Webpack 支援預先載入或預先擷取動態匯入的區塊。以這個應用程式為例,系統可在瀏覽器閒置時預先擷取 lodash 方法;當使用者按下該按鈕,擷取資源並沒有延遲。

在動態匯入中使用特定 webpackPrefetch 註解參數,即可預先擷取特定區塊。以下說明其在這個應用程式中的外觀。

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

應用程式重新載入後,Webpack 會將資源的預先擷取標記插入文件標頭。您可以在開發人員工具的「Elements」面板中查看這項資訊。

具有預先擷取標記的元素面板

查看「Network」面板中的要求時,也會顯示在系統要求所有其他資源後,以低優先順序擷取這個區塊。

含有預先擷取要求的網路面板

雖然預先擷取較適合這種用途,但 webpack 也支援動態匯入的區塊。

import(/* webpackPreload: true */ 'module')

結語

透過本程式碼研究室,您應充分瞭解預先載入或預先擷取特定資產如何改善網站的使用者體驗。請特別注意,這些技巧不應用於每項資源,並不當使用,可能對效能造成不良影響。如要獲得最佳結果,我們只會預先載入或預先擷取內容。

摘要:

  • 針對較晚發現但對目前網頁至關重要的資源,請使用預先載入功能。
  • 針對日後導覽路徑或使用者動作所需資源,請使用「預先擷取」功能。

目前並非所有瀏覽器都支援預先載入和預先擷取功能。這意味著,應用程式的使用者不一定都會注意到效能有所提升。

如要進一步瞭解預先載入和預先擷取功能對網頁有何影響,請參閱下列文章: