缓存

安全上下文:此功能仅在安全上下文(HTTPS)中可用,在某些或所有支持的浏览器中可用。

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

Cache 接口为在长期内存中缓存的 Request / Response 对象对提供了一种持久性存储机制。Cache 对象的生命周期取决于浏览器,但单个来源的脚本通常可以依赖于先前填充的 Cache 对象的存在。请注意,Cache 接口既公开给窗口范围,也公开给工作线程。即使它是在 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 下方的“检查”链接以查看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);
          }
        }),
      ),
    ),
  );
});

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

  event.respondWith(
    caches.open(CURRENT_CACHES.font).then((cache) => {
      return 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.org.cn/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.org.cn/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 和缓存对象

Fetch API 要求在从fetch() 返回Response 对象之前,先剥离Set-Cookie 标头。因此,存储在 Cache 中的 Response 不会包含 Set-Cookie 标头,因此不会导致存储任何 Cookie。

规范

规范
Service Workers
# cache-interface

浏览器兼容性

BCD 表仅在启用 JavaScript 的浏览器中加载。

另请参阅