Service Worker 快取的策略

到目前為止,只有提及 Cache 介面。 如要有效運用服務工作處理程序,必須採用一或多項快取策略。 ,這需要稍微熟悉 Cache 介面。

快取策略是指服務工作處理程序的 fetch 事件與 Cache 介面之間的互動。 快取策略的編寫方式取決於: 舉例來說,處理靜態資產的要求可能最好與文件不同 這會影響快取策略的組成方式

在探討策略之前 我們來談談 Cache 介面是什麼 以及服務工作處理程序快取的一些方法快速彙整。

Cache 介面與 HTTP 快取

如果您未曾使用 Cache 介面, 你可能會想把它想像成 至少與 HTTP 快取相關但此聲明與事實不符。

  • Cache 介面是完全獨立於 HTTP 快取的快取機制。
  • 任何 Cache-Control 不會影響 HTTP 快取的設定,並不會影響 Cache 介面中儲存的資產。

您可以將瀏覽器快取視為分層。 HTTP 快取是一種低階快取,由鍵/值組合驅動,其中包含以 HTTP 標頭表示的指令。

相反地,Cache 介面是 JavaScript API 驅動的高階快取。 相較於使用相對簡單的 HTTP 鍵/值組合 也是快取策略可行的一半 Service Worker 快取的部分重要 API 方法如下:

此處列舉的只是其中幾例。還有其他實用方法 但這些是本指南稍後會用到的幾項基本功能

一覽 fetch 活動

快取策略的另一半是 Service Worker fetch 事件。 到目前為止,您已聽過「攔截網路要求」、 而 Service Worker 中的 fetch 事件發生位置:

// Establish a cache name
const cacheName = 'MyFancyCacheName_v1';

self.addEventListener('install', (event) => {
  event.waitUntil(caches.open(cacheName));
});

self.addEventListener('fetch', async (event) => {
  // Is this a request for an image?
  if (event.request.destination === 'image') {
    // Open the cache
    event.respondWith(caches.open(cacheName).then((cache) => {
      // Respond with the image from the cache or from the network
      return cache.match(event.request).then((cachedResponse) => {
        return cachedResponse || fetch(event.request.url).then((fetchedResponse) => {
          // Add the network response to the cache for future visits.
          // Note: we need to make a copy of the response to save it in
          // the cache and use the original as the request response.
          cache.put(event.request, fetchedResponse.clone());

          // Return the network response
          return fetchedResponse;
        });
      });
    }));
  } else {
    return;
  }
});

這是玩具範例 幫助您瞭解實際運作情形,但是 可讓服務人員一窺 Service 工作人員的魅力, 上述程式碼會執行以下作業:

  1. 檢查要求的 destination 屬性,確認這是圖片要求。
  2. 如果圖片在 Service Worker 快取中,請從這裡提供。 如果沒有,請從網路擷取圖片 將回應儲存在快取中,然後傳回網路回應。
  3. 所有其他要求都會透過 Service Worker 傳遞,但不會與快取互動。

擷取的 event 物件包含 request 資源 以下提供一些有用資訊,協助您識別每個要求的類型:

  • url、 這是目前由 fetch 事件處理的網路要求網址。
  • method、 也就是請求方法 (例如GETPOST)。
  • mode、 會說明要求的模式 'navigate' 值通常用於區分 HTML 文件和其他要求的要求。
  • destination、 ,描述如何避免使用所要求資產副檔名的方式請求的內容類型。

同理,非同步遊戲名稱就是遊戲名稱。 您會回想一下,install 事件提供了 event.waitUntil 並等待問題解決,再繼續啟用服務。 fetch 事件提供 event.respondWith 方法 您可用來傳回非同步 fetch要求 或是 Cache 介面的 match 方法

快取策略

現在,您已對 Cache 執行個體和 fetch 事件處理常式有初步的瞭解, 您已準備好深入瞭解一些 Service Worker 快取策略。 雖然可能性幾乎無窮無盡 本指南將沿用 Workbox 隨附的策略 方便您掌握 Workbox 內部團隊的動向。

僅快取

顯示從頁面到 Service Worker 到快取的流程。

我們先從簡單的快取策略開始,稱為「僅限快取」。 顧名思義,當 Service Worker 能控制頁面時 相符的要求只會傳送至快取。 也就是說,所有快取資產都必須預先快取 才能用於模式 而且在 Service Worker 更新之前,這些資產一律不會在快取中更新。

// Establish a cache name
const cacheName = 'MyFancyCacheName_v1';

// Assets to precache
const precachedAssets = [
  '/possum1.jpg',
  '/possum2.jpg',
  '/possum3.jpg',
  '/possum4.jpg'
];

self.addEventListener('install', (event) => {
  // Precache assets on install
  event.waitUntil(caches.open(cacheName).then((cache) => {
    return cache.addAll(precachedAssets);
  }));
});

self.addEventListener('fetch', (event) => {
  // Is this one of our precached assets?
  const url = new URL(event.request.url);
  const isPrecachedRequest = precachedAssets.includes(url.pathname);

  if (isPrecachedRequest) {
    // Grab the precached asset from the cache
    event.respondWith(caches.open(cacheName).then((cache) => {
      return cache.match(event.request.url);
    }));
  } else {
    // Go to the network
    return;
  }
});

上述內容陣列會在安裝時友善載入。 服務工作處理程序處理擷取作業時, 我們會檢查 fetch 事件處理的要求網址是否位於預先快取資產的陣列中。 如果有,我們會從快取中擷取資源,然後略過網路。 其他要求則會傳送到聯播網 只有網路 如要瞭解這項策略的實際運作方式, 開啟控制台後查看這個示範

僅限網路

顯示從頁面到 Service Worker 對網路的流程。

「僅快取」與相反情況是「僅限聯播網」 表示要求會透過 Service Worker 傳送到網路,但不會與 Service Worker 快取進行互動。 這個策略有助於確保內容新鮮度 (思維標記)、 但缺點是使用者離線時無法使用這項功能。

確保要求可通過網路只是表示您不會針對相符的要求呼叫 event.respondWith。 如果想明確呈現 您可以在 fetch 事件回呼中,針對要傳遞到網路的要求,執行空白的 return;。 這就是「僅限快取」中會發生的情況非預先載入要求的策略示範模式。

先快取,改回使用網路

顯示從網頁到 Service Worker,到快取的流量;如果不在快取中,則顯示從網路到網路的流程。

但這項策略會更加複雜。 對於比對要求,程序如下:

  1. 這項要求達到快取後,如果素材資源在快取中,請從該處提供。
  2. 如果要求「不在」快取中,請前往該網路。
  3. 網路要求完成後,請將其新增至快取 然後,從網路傳回回應

以下舉例說明這項策略 現場示範

// Establish a cache name
const cacheName = 'MyFancyCacheName_v1';

self.addEventListener('fetch', (event) => {
  // Check if this is a request for an image
  if (event.request.destination === 'image') {
    event.respondWith(caches.open(cacheName).then((cache) => {
      // Go to the cache first
      return cache.match(event.request.url).then((cachedResponse) => {
        // Return a cached response if we have one
        if (cachedResponse) {
          return cachedResponse;
        }

        // Otherwise, hit the network
        return fetch(event.request).then((fetchedResponse) => {
          // Add the network response to the cache for later visits
          cache.put(event.request, fetchedResponse.clone());

          // Return the network response
          return fetchedResponse;
        });
      });
    }));
  } else {
    return;
  }
});

雖然這個例子只涵蓋了圖片 對所有靜態素材資源 (例如 CSS、JavaScript、圖片和字型) 來說,這是不錯的策略 尤其是經過雜湊處理的版本 對不可變更的資產進行逐步檢查,讓 HTTP 快取能夠啟動任何可能啟動的內容更新間隔檢查,藉此提升處理不可變更的資產的速度。 更重要的是,所有快取資產都能離線使用。

以網路為優先,改回快取

顯示從頁面到 Service Worker,到網路的流程,如果沒有網路,則顯示快取。

如果您想翻轉「先快取,網路第二個」頭上 最終產生「網路優先,快取第二個」也就是定義策略

  1. 您應先前往網路發出要求,然後將回應放在快取中。
  2. 如果您在之後離線 您就會在快取中回復到該回應的最新版本。

這項策略適用於 HTML 或 API 要求。 您會希望取得最新版本的資源 還想讓離線存取功能維持在最新版本。 套用 HTML 要求時,看起來可能像這樣:

// Establish a cache name
const cacheName = 'MyFancyCacheName_v1';

self.addEventListener('fetch', (event) => {
  // Check if this is a navigation request
  if (event.request.mode === 'navigate') {
    // Open the cache
    event.respondWith(caches.open(cacheName).then((cache) => {
      // Go to the network first
      return fetch(event.request.url).then((fetchedResponse) => {
        cache.put(event.request, fetchedResponse.clone());

        return fetchedResponse;
      }).catch(() => {
        // If the network is unavailable, get
        return cache.match(event.request.url);
      });
    }));
  } else {
    return;
  }
});

你可以在示範中試用這項功能。 首先,請前往該網頁。您可能需要重新載入,才能將 HTML 回應放入快取。 接著在開發人員工具中 模擬離線連線、 然後重新嘗試。 系統會立即從快取提供最後一個可用版本。

離線作業很重要的情況下 但您需要在功能存取權與最新版本的標記或 API 資料存取權之間取得平衡。 「網路優先,快取第二個」 是能達成這個目標的可靠策略。

過時程度重新驗證

顯示從網頁到 Service Worker 到快取,再從網路到快取的流程。

到目前為止,我們已介紹的策略「過時的重新驗證」最複雜 它在某些方面與最後兩項策略類似 但本程序會將資源存取速度列為優先考量 同時在背景中保持最新狀態此策略包括:

  1. 第一次收到資產的要求時,請從網路擷取該資產。 放到快取中,然後傳回網路回應。
  2. 在後續的要求中,先從快取提供素材資源,然後「在背景中」。 重新向網路要求該資源,並更新資產的快取項目。
  3. 針對之後的要求 您會在前一個步驟中,從網路擷取的最後一個版本。

對於需要跟上更新相關的動作來說,這個策略很實用 但不為關鍵 您可以把網站當成社群媒體網站的顯示圖片, 並且會在使用者外出時更新 但並非每次要求都會需要最新版本。

// Establish a cache name
const cacheName = 'MyFancyCacheName_v1';

self.addEventListener('fetch', (event) => {
  if (event.request.destination === 'image') {
    event.respondWith(caches.open(cacheName).then((cache) => {
      return cache.match(event.request).then((cachedResponse) => {
        const fetchedResponse = fetch(event.request).then((networkResponse) => {
          cache.put(event.request, networkResponse.clone());

          return networkResponse;
        });

        return cachedResponse || fetchedResponse;
      });
    }));
  } else {
    return;
  }
});

您可以在以下位置查看實際運作情形: 這是另一個實際示範 尤其在註意 瀏覽器開發人員工具中的「網路」分頁時 及其 CacheStorage 檢視器 (如果瀏覽器的開發人員工具有這類工具)。

前往 Workbox!

本文件總結了 Service Worker API 的審查結果。 以及相關 API 這表示您已充分瞭解如何直接使用服務工作處理程序,開始設計 Workbox!