Cache

Baseline 已廣泛支援

此功能已成熟,可跨多種裝置和瀏覽器版本工作。它自 ⁨2018 年 4 月⁩ 起已在所有瀏覽器中可用。

安全上下文: 此功能僅在安全上下文(HTTPS)中可用,且支援此功能的瀏覽器數量有限。

注意:此功能在 Web Workers 中可用。

Cache 介面提供了一種持久化儲存機制,用於儲存 Request / Response 物件對,這些物件被快取在長壽命記憶體中。Cache 物件的生命週期取決於瀏覽器,但單個源的指令碼通常可以依賴於先前填充的 Cache 物件。請注意,Cache 介面既暴露給視窗作用域,也暴露給 worker。您不必將其與 service worker 結合使用,即使它是在 service worker 規範中定義的。

一個源可以有多個命名 Cache 物件。您負責實現指令碼(例如,在 ServiceWorker 中)如何處理 Cache 更新。Cache 中的專案不會自動更新,除非明確請求;它們不會過期,除非被刪除。使用 CacheStorage.open() 來開啟特定的命名 Cache 物件,然後呼叫任何 Cache 方法來維護 Cache

您還負責定期清理快取條目。每個瀏覽器對給定源可以使用的快取儲存量都有硬性限制。可以透過 StorageManager.estimate() 方法估算 Cache 配額使用情況。瀏覽器會盡最大努力管理磁碟空間,但它可能會刪除源的 Cache 儲存。瀏覽器通常會刪除一個源的所有資料,或者不刪除任何資料。請確保透過名稱對快取進行版本化,並僅使用可以安全操作它們的指令碼版本中的快取。有關更多資訊,請參閱 刪除舊快取

注意: 鍵匹配演算法取決於值的 VARY 頭。因此,匹配新鍵需要檢視 Cache 物件中條目的鍵和值。

注意: 快取 API 不遵守 HTTP 快取頭。

例項方法

Cache.match()

返回一個 Promise,該 Promise 解析為 Cache 物件中第一個匹配請求的響應。

Cache.matchAll()

返回一個 Promise,該 Promise 解析為 Cache 物件中所有匹配響應的陣列。

Cache.add()

接收一個 URL,檢索它,並將結果響應物件新增到給定的快取中。這在功能上等同於呼叫 fetch(),然後使用 put() 將結果新增到快取。

Cache.addAll()

接收一個 URL 陣列,檢索它們,並將結果響應物件新增到給定的快取中。

Cache.put()

接收請求及其響應,並將它們新增到給定的快取中。

Cache.delete()

查詢鍵為請求的 Cache 條目,返回一個 Promise,如果找到並刪除了匹配的 Cache 條目,則該 Promise 解析為 true。如果未找到 Cache 條目,則 Promise 解析為 false

Cache.keys()

返回一個 Promise,該 Promise 解析為 Cache 鍵的陣列。

示例

此程式碼片段來自 service worker 選擇性快取示例。(請參閱 選擇性快取即時演示) 程式碼使用 CacheStorage.open() 來開啟任何 Content-Type 頭以 font/ 開頭的 Cache 物件。

然後,程式碼使用 Cache.match() 來檢查快取中是否已有匹配的字型,如果有,則返回它。如果不存在匹配的字型,程式碼將從網路獲取字型,並使用 Cache.put() 將獲取的資源快取起來。

程式碼處理從 fetch() 操作丟擲的異常。請注意,HTTP 錯誤響應(例如 404)不會引發異常。它將返回一個具有相應錯誤程式碼的正常響應物件。

程式碼片段還展示了 service worker 使用的快取版本化的最佳實踐。雖然在此示例中只有一個快取,但相同的方法可用於多個快取。它將快取的簡短識別符號對映到特定的、版本化的快取名稱。程式碼還會刪除所有未在 CURRENT_CACHES 中命名的快取。

在程式碼示例中,cachesServiceWorkerGlobalScope 的一個屬性。它包含 CacheStorage 物件,透過它可以訪問 CacheStorage 介面。

注意: 在 Chrome 中,訪問 chrome://inspect/#service-workers 並點選已註冊的 service worker 下方的“inspect”連結,可以檢視 service-worker.js 指令碼執行的各種操作的日誌記錄語句。

js
const CACHE_VERSION = 1;
const CURRENT_CACHES = {
  font: `font-cache-v${CACHE_VERSION}`,
};

self.addEventListener("activate", (event) => {
  // Delete all caches that aren't named in CURRENT_CACHES.
  // While there is only one cache in this example, the same logic
  // will handle the case where there are multiple versioned caches.
  const expectedCacheNamesSet = new Set(Object.values(CURRENT_CACHES));
  event.waitUntil(
    caches.keys().then((cacheNames) =>
      Promise.all(
        cacheNames.map((cacheName) => {
          if (!expectedCacheNamesSet.has(cacheName)) {
            // If this cache name isn't present in the set of
            // "expected" cache names, then delete it.
            console.log("Deleting out of date cache:", cacheName);
            return caches.delete(cacheName);
          }
          return undefined;
        }),
      ),
    ),
  );
});

self.addEventListener("fetch", (event) => {
  console.log("Handling fetch event for", event.request.url);

  event.respondWith(
    caches
      .open(CURRENT_CACHES.font)
      .then((cache) => cache.match(event.request))
      .then((response) => {
        if (response) {
          // If there is an entry in the cache for event.request,
          // then response will be defined and we can just return it.
          // Note that in this example, only font resources are cached.
          console.log(" Found response in cache:", response);

          return response;
        }

        // Otherwise, if there is no entry in the cache for event.request,
        // response will be undefined, and we need to fetch() the resource.
        console.log(
          " No response for %s found in cache. About to fetch " +
            "from network…",
          event.request.url,
        );

        // We call .clone() on the request since we might use it
        // in a call to cache.put() later on.
        // Both fetch() and cache.put() "consume" the request,
        // so we need to make a copy.
        // (see https://mdn.club.tw/en-US/docs/Web/API/Request/clone)
        return fetch(event.request.clone()).then((response) => {
          console.log(
            "  Response for %s from network is: %O",
            event.request.url,
            response,
          );

          if (
            response.status < 400 &&
            response.headers.has("content-type") &&
            response.headers.get("content-type").match(/^font\//i)
          ) {
            // This avoids caching responses that we know are errors
            // (i.e. HTTP status code of 4xx or 5xx).
            // We also only want to cache responses that correspond
            // to fonts, i.e. have a Content-Type response header that
            // starts with "font/".
            // Note that for opaque filtered responses
            // https://fetch.spec.whatwg.org/#concept-filtered-response-opaque
            // we can't access to the response headers, so this check will
            // always fail and the font won't be cached.
            // All of the Google Web Fonts are served from a domain that
            // supports CORS, so that isn't an issue here.
            // It is something to keep in mind if you're attempting
            // to cache other resources from a cross-origin
            // domain that doesn't support CORS, though!
            console.log("  Caching the response to", event.request.url);
            // We call .clone() on the response to save a copy of it
            // to the cache. By doing so, we get to keep the original
            // response object which we will return back to the controlled
            // page.
            // https://mdn.club.tw/en-US/docs/Web/API/Request/clone
            cache.put(event.request, response.clone());
          } else {
            console.log("  Not caching the response to", event.request.url);
          }

          // Return the original response object, which will be used to
          // fulfill the resource request.
          return response;
        });
      })
      .catch((error) => {
        // This catch() will handle exceptions that arise from the match()
        // or fetch() operations.
        // Note that a HTTP error response (e.g. 404) will NOT trigger
        // an exception.
        // It will return a normal response object that has the appropriate
        // error code set.
        console.error("  Error in fetch handler:", error);

        throw error;
      }),
  );
});

Cookie 和 Cache 物件

Fetch API 要求在從 fetch() 返回 Response 物件之前,刪除 Set-Cookie 頭。因此,儲存在 Cache 中的 Response 將不包含 Set-Cookie 頭,因此不會導致任何 Cookie 被儲存。

規範

規範
Service Workers
# cache-interface

瀏覽器相容性

另見