Cache - 为 Request / Response 对象提供了一种存储机制

Cache 接口为 Request / Response 对象提供了一种存储机制,例如作为 ServiceWorker 生命周期的一部分。请注意,Cache 接口暴露给窗口范围以及工作线程。即使它是在 Service Worker 规范中定义的,但是除了服务工作线程之外,您还可以与其他的功能一起使用它。

一个源可以有多个名为 Cache 的对象。您需要负责实现您的脚本(例如,在 ServiceWorker 中)如何处理 Cache 更新。除非明确要求,否则 Cache 中的项目不会更新。除非删除,否则它们不会过期。您可以使用 CacheStorage.open() 打开指定名称的 Cache 对象,然后调用任何 Cache 方法以维护 Cache

您还需要负责定期清除缓存条目。每个浏览器对给定源可以使用的缓存存储量都有硬性限制。可通过 StorageEstimate API 获得缓存配额使用估算值。浏览器会尽力管理磁盘空间,但可能会删除源存储的缓存。浏览器通常会删除源的所有数据,或者不删除源的任何数据。请确保按名称对缓存进行版本控制,并仅从能够安全操作的脚本版本使用缓存。有关更多信息,请参见删除旧缓存

注意: 键名匹配算法取决于值中的 VARY 标头。因此,匹配新密钥需要同时查看缓存中条目的键名和值。

注意: 缓存 API 不支持 HTTP 缓存头。

方法

Cache.match(request, options)

返回一个 Promise,解析为与 Cache 对象中第一个匹配请求相关联的响应。

Cache.matchAll(request, options)

返回一个 Promise,解析为 Cache 对象中所有匹配请求的数组。

Cache.add(request)

传入一个 URL,将其检索并将结果响应对象添加到给定的缓存中。这在功能上等同于调用 fetch() ,然后使用 put() 将结果添加到缓存中。

Cache.addAll(requests)

传入一个 URL 数组,检索它们,并将结果响应对象添加到给定的缓存中。

Cache.put(request, response)

接受请求及其响应,并将其添加到给定的缓存中。

Cache.delete(request, options)

查找键为请求的 Cache 条目,并返回一个 Promise,如果找到并删除了匹配的 Cache 条目,则解析为 true。如果没有找到 Cache 条目,则承诺解析为 false

Cache.keys(request, options)

返回一个 Promise,解析为包含 Cache 键名的数组。

实例

此代码段来自服务工作线程选择性缓存实例。 (请参阅选择性缓存在线实例)该代码使用 CacheStorage.open() 打开任何以 font/ 开头的 Content-Type 标头的 Cache 对象。

然后,代码使用 Cache.match() 来查看缓存中是否已经有匹配的字体,如果有,则返回它。如果没有匹配的字体,则代码将从网络中获取字体,并使用 Cache.put() 来缓存获取的资源。

该代码处理从 fetch() 操作引发的异常。注意,HTTP 错误响应(例如 404)不会触发异常。它将返回具有相应错误代码的普通响应对象。

该代码段还显示了服务工作线程使用的版本缓存的最佳实践。尽管此实例中只有一个缓存,但是相同的方法可以用于多个缓存。它将高速缓存的速记标识符映射到特定的版本化高速缓存名称。该代码还将删除所有未在 CURRENT_CACHES 中命名的缓存。

在代码实例中,cachesServiceWorkerGlobalScope 的属性。它包含了 CacheStorage 对象,通过它可以访问 CacheStorage 接口。这是 WindowOrWorkerGlobalScope mixin 的实现。

注意: 在 Chrome 浏览器中,访问 chrome://inspect/#service-workers,然后点击注册的服务工作线程下方的 “检查” 链接,以查看 service-worker.js 脚本正在执行的各种操作的日志记录。

var CACHE_VERSION = 1;
var CURRENT_CACHES = {
  font: 'font-cache-v' + CACHE_VERSION
};

self.addEventListener('activate', function(event) {
  // 删除所有未在 CURRENT_CACHES 中命名的缓存。
  // 虽然在此实例中只有一个缓存,但是可以使用相同的逻辑来处理存在多个版本化缓存的情况。
  var expectedCacheNamesSet = new Set(Object.values(CURRENT_CACHES));
  event.waitUntil(
    caches.keys().then(function(cacheNames) {
      return Promise.all(
        cacheNames.map(function(cacheName) {
          if (!expectedCacheNamesSet.has(cacheName)) {
            // 如果预期的缓存名称没有该缓存名称,则将其删除。
            console.log('删除过期缓存:', cacheName);
            return caches.delete(cacheName);
          }
        })
      );
    })
  );
});

self.addEventListener('fetch', function(event) {
  console.log('处理的提取事件', event.request.url);

  event.respondWith(
    caches.open(CURRENT_CACHES.font).then(function(cache) {
      return cache.match(event.request).then(function(response) {
        if (response) {
          // 如果缓存中有一个用于 event.request 的条目,则将定义响应,我们可以将其返回。
          // 请注意,在此实例中,仅字体资源被缓存。
          console.log('在缓存中找到响应:', response);

          return response;
        }

        // 否则,如果高速缓存中没有 event.request 的条目,则响应将是 undefined,
        // 因此我们需要 fetch() 来获取资源。
        console.log('在缓存中找不到%s 的响应。即将从网络中获取...', event.request.url);

        // 我们在请求上调用 .clone(),因为稍后可能会在调用 cache.put() 时使用它。
        // fetch() 和 cache.put() 都 “消耗” 请求,因此我们需要进行复制。
        return fetch(event.request.clone()).then(function(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)) {
            // 这避免了缓存错误的响应(即 HTTP 状态代码 4xx 或 5xx)。
            // 我们只想缓存与字体相对应的响应,即具有以 `font/` 开头的 `Content-Type` 响应头。
            // 请注意,对于不透明的已过滤响应(https://fetch.spec.whatwg.org/#concept-filtered-response-opaque),我们无法访问响应标头,因此此检查将始终失败并且字体不会被缓存。
            // 所有的谷歌 Web 字体都是在支持 CORS 的域之外提供的,所以这不是问题。
            // 但是,如果您尝试从不支持 CORS 的跨域域中缓存其他资源,则要记住这一点!
            // 我们在响应上调用 .clone(),将其副本保存到缓存中。
            // 这样,我们保留了原始响应对象,该对象将返回到受控页面。
            console.log('  Caching the response to', event.request.url);
            cache.put(event.request, response.clone());
          } else {
            console.log('  Not caching the response to', event.request.url);
          }

          // 返回原始响应对象,该对象将用于满足资源请求。
          return response;
        });
      }).catch(function(error) {
        // 这个 catch() 将处理 match() 或 fetch() 操作引起的异常。
        // 请注意,HTTP 错误响应(例如 404)不会触发异常。
        // 它将返回一个具有相应错误代码集的普通响应对象。
        console.error('featch 处理程序中的错误:', error);

        throw error;
      });
    })
  );
});

Fetch API 要求先删除 Set-Cookie 标头,然后再从 fetch() 返回 Response 对象。因此,存储在缓存中的 Response 将不包含标头。

规范

规范 状态 备注
Service Workers
Cache 的定义
工作草案 初始定义。

桌面浏览器兼容性

特性ChromeEdgeFirefoxInternet ExplorerOperaSafari
基础支持431≤18392 不支持30311
add44416392 不支持31511
addAll46716392 不支持33711
delete4316392 不支持3011
keys4316392 不支持3011
match4316392 不支持3011
matchAll4716392 不支持34711
put43416392 不支持30511

移动浏览器兼容性

特性AndroidChrome for AndroidEdge mobileFirefox for AndroidIE mobileOpera AndroidiOS Safari
基础支持431431 未知39 未知303 不支持
add444444 未知39 未知325 不支持
addAll467467 未知39 未知337 不支持
delete4343 未知39 未知30 不支持
keys4343 未知39 未知30 不支持
match4343 未知39 未知30 不支持
matchAll4747 未知39 未知34 不支持
put434434 未知39 未知305 不支持

1. 从版本 40 到 42,仅适用于服务工作线程。

2. 在 Firefox 45 和 52 扩展支持版本(ESR)中,服务工作线程(和 Push)已被禁用。

3. 从版本 27 到 29,仅适用于服务工作线程。

4. 从版本 46 开始 HTTPS 下才可用。

5. 从版本 33 开始 HTTPS 下才可用。

6. 从 Samsung Internet 5.0 开始 HTTPS 下才可用。

7. Requires HTTPS.

相关链接