Cache API
一句话: Cache API(caches 全局对象)是一个持久化的、按来源划分的 Request/Response 对键值存储。Service worker 用它在 install 期间存储资源并在离线时提供服务;与浏览器 HTTP 缓存不同,Cache API 完全可编程——不经你的代码操作,没有任何内容会被存入或清除。
caches 全局对象
Section titled “caches 全局对象”caches 是一个 CacheStorage 实例,在 service worker 和页面中均可使用(Chrome 43 / Firefox 41 起支持)。它管理一组具名 Cache 对象。
// service worker 和页面中均可使用const cache = await caches.open('my-cache-v1');const cache = await caches.open('app-shell-v3');若缓存不存在,caches.open() 会自动创建。缓存名称是任意字符串;使用带版本号的名称(app-shell-v3),便于在 activate 中删除旧缓存。
cache.add(request) — 获取并存储单个资源
Section titled “cache.add(request) — 获取并存储单个资源”await cache.add('/offline.html'); // 先 fetch,再存储cache.addAll(requests) — 原子地获取并存储多个资源
Section titled “cache.addAll(requests) — 原子地获取并存储多个资源”await cache.addAll([ '/', '/app.js', '/app.css', '/offline.html',]);addAll 是原子操作:若任意请求失败,所有内容均不会存储。在 install 中配合 event.waitUntil() 使用,可确保预缓存失败时中止安装。
cache.put(request, response) — 存储已有的响应
Section titled “cache.put(request, response) — 存储已有的响应”const response = await fetch(event.request);await cache.put(event.request, response.clone());put 不发起请求——它直接存储你传入的 Response。若既要存储又要返回响应,必须先调用 clone()(响应是单次读取的流)。
cache.match(request, options?) — 查找单个条目
Section titled “cache.match(request, options?) — 查找单个条目”const cached = await cache.match('/app.js');if (cached) return cached;caches.match(request) — 按插入顺序查询所有缓存
Section titled “caches.match(request) — 按插入顺序查询所有缓存”const cached = await caches.match(event.request);caches.match() 搜索所有已打开的缓存并返回第一个匹配项。不确定资源在哪个缓存中时很有用。
await cache.match(request, { ignoreSearch: true, // 忽略查询字符串(?v=1) ignoreMethod: true, // 将 POST 视为 GET 匹配 ignoreVary: true, // 忽略 Vary 头});删除条目与缓存
Section titled “删除条目与缓存”// 从缓存中删除单个条目await cache.delete('/old-resource.js');
// 删除整个具名缓存await caches.delete('app-shell-v2');
// 列出所有缓存名称const names = await caches.keys();标准做法是在新版本安装后,在 activate 事件中删除旧缓存:
self.addEventListener('activate', (event) => { event.waitUntil( caches.keys().then((names) => Promise.all( names .filter((n) => n !== 'app-shell-v3') // 只保留当前缓存 .map((n) => caches.delete(n)) ) ) );});Cache Storage 受来源存储配额约束(与 IndexedDB、OPFS 等存储 API 共享)。当设备存储空间紧张时,浏览器会从最近未使用的来源开始清除数据——除非该来源已申请持久化存储。详见持久化、配额与清除策略。
缓存不透明响应
Section titled “缓存不透明响应”以 no-cors 方式获取的跨域响应是不透明的(status: 0,body 不可读)。你可以缓存不透明响应,但需注意:
- 无法检查其状态码以确认是否成功。
- 可能被计为较大条目(浏览器会在配额计算中填充不透明响应,以防止时序攻击)。
- 过期的不透明响应与失败的响应无法区分。
缓存中优先使用同源或已启用 CORS 的资源。若必须缓存不透明响应,始终搭配重新验证策略使用。
- 为缓存名称加版本号(
shell-v3而非shell),并在activate中删除旧版本。 - 在
install中使用cache.addAll()原子地预缓存应用外壳。 - 调用
cache.put()前若还需返回响应,务必先clone()一份。 - 明确知道资源在哪个缓存中时,优先使用
cache.match()而非caches.match()——速度更快。 - 通过 DevTools → 应用 → 存储监控存储用量,防止配额悄悄增长。
- 缓存策略 — 使用 Cache API 的各种模式
- Fetch 事件与路由 — 请求时调用
caches.match()的位置 - 持久化、配额与清除策略 — 存储配额与清除策略