CacheStorage

Baseline 已廣泛支援

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

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

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

CacheStorage 介面代表 Cache 物件的儲存。

該介面

  • 提供了一個主目錄,其中包含所有命名的快取,這些快取可以由 ServiceWorker 或其他型別的 worker 或 window 作用域訪問(您不限於僅將它與 Service Worker 一起使用)。
  • 維護一個從字串名稱到相應的 Cache 物件的對映。

使用 CacheStorage.open() 來獲取一個 Cache 例項。

使用 CacheStorage.match() 來檢查給定的 Request 是否是 CacheStorage 物件跟蹤的任何 Cache 物件中的一個鍵。

您可以透過視窗中的 Window.caches 屬性或在 worker 中的 WorkerGlobalScope.caches 屬性來訪問 CacheStorage

注意: CacheStorage 始終會在不受信任的源(即未使用的 HTTPS 的源)上因 SecurityError 而拒絕(儘管此定義將來可能會變得更復雜)。在 Firefox 上進行測試時,您可以透過在 Firefox DevTools 的選項/齒輪選單中選中“在 HTTP 上啟用 Service Worker(當工具箱開啟時)”選項來繞過此限制。此外,由於 CacheStorage 需要檔案系統訪問,因此在 Firefox 的私有模式下可能不可用。

注意: CacheStorage.match() 是一個便捷方法。透過從 CacheStorage.keys() 返回快取名稱的陣列,使用 CacheStorage.open() 開啟每個快取,並使用 Cache.match() 匹配您想要的快取,可以實現匹配快取條目的等效功能。

例項方法

CacheStorage.match()

檢查給定的 Request 是否是 CacheStorage 物件跟蹤的任何 Cache 物件中的一個鍵,並返回一個解析為該匹配項的 Promise

CacheStorage.has()

返回一個 Promise,該 Promise 解析為 true,如果存在匹配 cacheNameCache 物件。

CacheStorage.open()

返回一個 Promise,該 Promise 解析為匹配 cacheNameCache 物件(如果尚不存在,則建立一個新的快取)。

CacheStorage.delete()

查詢匹配 cacheNameCache 物件,如果找到,則刪除該 Cache 物件並返回一個解析為 truePromise。如果未找到 Cache 物件,則解析為 false

CacheStorage.keys()

返回一個 Promise,它將解析為一個數組,其中包含對應於 CacheStorage 跟蹤的所有命名 Cache 物件的字串。使用此方法可以遍歷所有 Cache 物件列表。

示例

此程式碼段摘自 MDN 的 簡單 Service Worker 示例(請參閱 線上執行的簡單 Service Worker)。此 Service Worker 指令碼等待 install 事件觸發,然後執行 waitUntil 來處理應用程式的安裝過程。這包括呼叫 CacheStorage.open 來建立一個新快取,然後使用 Cache.addAll 將一系列資源新增到其中。

在第二個程式碼塊中,我們等待 FetchEvent 事件觸發。我們像這樣構造一個自定義響應:

  1. 檢查是否在 CacheStorage 中找到請求的匹配項。如果找到,則提供該匹配項。
  2. 如果未找到,則從網路獲取請求,然後開啟第一個塊中建立的快取,並使用 Cache.put 將請求的克隆新增到其中(cache.put(event.request, response.clone()))。
  3. 如果失敗(例如,因為網路中斷),則返回一個備用響應。

最後,使用 FetchEvent.respondWith 返回最終的自定義響應。

js
self.addEventListener("install", (event) => {
  event.waitUntil(
    caches
      .open("v1")
      .then((cache) =>
        cache.addAll([
          "/",
          "/index.html",
          "/style.css",
          "/app.js",
          "/image-list.js",
          "/star-wars-logo.jpg",
          "/gallery/bountyHunters.jpg",
          "/gallery/myLittleVader.jpg",
          "/gallery/snowTroopers.jpg",
        ]),
      ),
  );
});

self.addEventListener("fetch", (event) => {
  event.respondWith(
    caches.match(event.request).then((response) => {
      // caches.match() always resolves
      // but in case of success response will have value
      if (response !== undefined) {
        return response;
      }
      return fetch(event.request)
        .then((response) => {
          // response may be used only once
          // we need to save clone to put one copy in cache
          // and serve second one
          let responseClone = response.clone();

          caches
            .open("v1")
            .then((cache) => cache.put(event.request, responseClone));
          return response;
        })
        .catch(() => caches.match("/gallery/myLittleVader.jpg"));
    }),
  );
});

此程式碼段展示瞭如何在 Service Worker 上下文之外使用該 API,並使用 await 運算子使程式碼更易讀。

js
// Try to get data from the cache, but fall back to fetching it live.
async function getData() {
  const cacheVersion = 1;
  const cacheName = `myapp-${cacheVersion}`;
  const url = "https://jsonplaceholder.typicode.com/todos/1";
  let cachedData = await getCachedData(cacheName, url);

  if (cachedData) {
    console.log("Retrieved cached data");
    return cachedData;
  }

  console.log("Fetching fresh data");

  const cacheStorage = await caches.open(cacheName);
  await cacheStorage.add(url);
  cachedData = await getCachedData(cacheName, url);
  await deleteOldCaches(cacheName);

  return cachedData;
}

// Get data from the cache.
async function getCachedData(cacheName, url) {
  const cacheStorage = await caches.open(cacheName);
  const cachedResponse = await cacheStorage.match(url);

  if (!cachedResponse || !cachedResponse.ok) {
    return false;
  }

  return await cachedResponse.json();
}

// Delete any old caches to respect user's disk space.
async function deleteOldCaches(currentCache) {
  const keys = await caches.keys();

  for (const key of keys) {
    const isOurCache = key.startsWith("myapp-");
    if (currentCache === key || !isOurCache) {
      continue;
    }
    caches.delete(key);
  }
}

try {
  const data = await getData();
  console.log({ data });
} catch (error) {
  console.error({ error });
}

規範

規範
Service Workers
# cachestorage-interface

瀏覽器相容性

另見