免安裝導覽體驗

透過服務工作者補足傳統預先載入技術。

在網站上執行任務通常需要完成多個步驟。舉例來說,在電子商務網站上購買產品可能會涉及搜尋產品、從結果清單中挑選商品、將商品加入購物車,以及透過結帳完成操作。

從技術層面來說,瀏覽不同頁面就是發出導覽要求。一般來說,您不應使用長效 Cache-Control 標頭,為導覽要求快取 HTML 回應。通常應透過網路和 Cache-Control: no-cache 滿足這些需求,確保 HTML 和後續網路要求鏈結 (合理) 保持新鮮。每次使用者前往新網頁時都必須透過網路,因此每個導覽可能都會變慢,至少不會穩定地快速。

為了加快這些要求的速度,如果您可以預測使用者的動作,可以事先要求這些網頁和素材資源,並將這些內容保留在快取中一段時間,直到使用者點選這些連結為止。這種做法稱為「預先載入」prefetching,通常會在網頁中加入 <link rel="prefetch"> 標記,指出要預先載入的資源。

在本指南中,我們將探討服務工作者可用於補足傳統預先擷取技術的各種方式。

實際工作環境案例

MercadoLibre 是拉丁美洲最大的電子商務網站。為了加快導覽速度,這些程式會在流程的部分部分動態插入 <link rel="prefetch"> 標記。舉例來說,在資訊頁面中,只要使用者捲動到資訊底部,系統就會擷取下一頁的結果:

MercadoLibre 的產品資訊頁面 1 和 2 的螢幕截圖,以及連結預先快取標記,用於連結兩個頁面。

預先擷取的檔案會以「最低」優先順序要求,並儲存在 HTTP 快取記憶體快取中 (視資源是否可快取而定),時間長短視瀏覽器而定。舉例來說,在 Chrome 85 中,這個值為 5 分鐘。資源會保留五分鐘,之後就會套用資源的一般 Cache-Control 規則。

使用服務工作者快取功能,有助於延長預先快取資源的生命週期,超過五分鐘的時間範圍。

舉例來說,義大利體育網站 Virgilio Sport 使用服務工作者,在首頁預先擷取最熱門的貼文。他們也會使用 Network Information API,避免為使用 2G 連線的使用者預先載入。

Virgilio Sport 標誌。

因此,在觀察了 3 週後,Virgilio Sport 的文章導覽載入時間改善了 78%,文章曝光次數也增加了 45%

Virgilio Sport 主畫面和文章頁面的螢幕截圖,以及預先載入後的影響指標。

使用 Workbox 實作預先快取

在下一節中,我們將使用 Workbox 說明如何在服務工作站中實作不同的快取技術,以便在將此工作完全委派給服務工作站時,做為 <link rel="prefetch"> 的補充,甚至是替代方案。

1. 預先快取靜態網頁和網頁子資源

預先快取是指服務工作者在安裝時,將檔案儲存到快取的功能。

在以下情況下,預先快取可用於達成與預先載入相同的目標:加快導覽速度。

預先快取靜態網頁

如果是建構期間產生的網頁 (例如 about.htmlcontact.html),或是完全靜態網站,您只需將網站文件加入預快取清單,這樣使用者每次存取時,這些文件就會在快取中提供:

workbox.precaching.precacheAndRoute([
  {url: '/about.html', revision: 'abcd1234'},
  // ... other entries ...
]);

預先快取網頁子資源

一般最佳做法是預先快取網站不同部分可能會使用的靜態素材資源 (例如 JavaScript、CSS 等),這樣做可在預先快取情境中提供額外提升效果。

如要加快電子商務網站中的導覽速度,您可以在產品資訊頁面中使用 <link rel="prefetch"> 標記,為產品資訊頁面中前幾項產品的產品詳細資料頁面預先載入。如果您已預先快取產品頁面子資源,這項功能還能讓導覽速度更快。

實作方式如下:

  • 在頁面中加入 <link rel="prefetch"> 標記:
 <link rel="prefetch" href="/phones/smartphone-5x.html" as="document">
  • 將網頁子資源新增至服務 worker 中的預先快取清單:
workbox.precaching.precacheAndRoute([
  '/styles/product-page.ac29.css',
  // ... other entries ...
]);

2. 延長預先載入資源的生命週期

如先前所述,<link rel="prefetch"> 會在 HTTP 快取中擷取及保留資源一段時間,之後資源的 Cache-Control 規則就會套用。在 Chrome 85 中,這個值為 5 分鐘。

服務工作者可讓您延長預先載入頁面的生命週期,同時提供額外的好處,讓這些資源可供離線使用。

在前述範例中,您可以使用 Workbox 執行階段快取策略,補充用於預先擷取產品頁面的 <link rel="prefetch">

實作方式如下:

  • 在頁面中加入 <link rel="prefetch"> 標記:
 <link rel="prefetch" href="/phones/smartphone-5x.html" as="document">
  • 針對以下類型的要求,在服務工作站中實作執行階段快取策略:
new workbox.strategies.StaleWhileRevalidate({
  cacheName: 'document-cache',
  plugins: [
    new workbox.expiration.Plugin({
      maxAgeSeconds: 30 * 24 * 60 * 60, // 30 Days
    }),
  ],
});

在本例中,我們選擇使用「Stale-while-revalidate」策略。在這種策略中,系統可以同時從快取和網路要求網頁。回應會從快取 (如有) 取得,如果沒有,則從網路取得。每次成功要求時,快取都會與網路回應保持一致。

3. 將預先載入工作委派給服務工作站

在大多數情況下,使用 <link rel="prefetch"> 是最佳做法。這個標記是資源提示,旨在盡可能提高預先載入的效率。

不過,在某些情況下,將這項工作完全委派給服務工作可能會比較好。舉例來說,如要在用戶端算繪的產品資訊頁面中預先擷取前幾項產品,可能需要根據 API 回應,在頁面中動態插入多個 <link rel="prefetch"> 標記。這可能會暫時耗用網頁主執行緒的時間,並使實作更加困難。

在這種情況下,請使用「頁面至服務工作程溝通策略」,將預先載入的任務完全委派給服務工作程。您可以使用 worker.postMessage() 實現這類通訊:

與服務工作單元進行雙向通訊的網頁圖示。

Workbox Window 套件可簡化這類通訊,抽象化底層呼叫的許多細節。

您可以透過下列方式實作 Workbox 視窗的預先載入功能:

  • 在頁面中:呼叫 Service Worker,並傳遞訊息類型和要預先載入的網址清單:
const wb = new Workbox('/sw.js');
wb.register();

const prefetchResponse = await wb.messageSW({type: 'PREFETCH_URLS', urls: []});
  • 在 Service Worker 中:實作訊息處理常式,針對每個要預先載入的網址發出 fetch() 要求:
addEventListener('message', (event) => {
  if (event.data.type === 'PREFETCH_URLS') {
    // Fetch URLs and store them in the cache
  }
});