Skip to content

参考

基于 MDN(Cache / CacheStorage / Using_Service_Workers)+ web.dev + Chrome Workbox 官方文档编写,对照 Cache API Baseline(2018-04)/ SW API / Workbox v7

速查

  • 核心 APIcaches.open/match/has/delete/keys(CacheStorage)+ cache.match/matchAll/add/addAll/put/delete/keys(Cache)
  • 5 策略:cache-only / network-only / cache-first(哈希静态)/ network-first(HTML·API)/ stale-while-revalidate(头像·字体)
  • 生命周期:install → waiting → activate → controlled;skipWaiting + clients.claim 仅用于紧急热修复
  • 导航预加载navigationPreload.enable() + await event.preloadResponse,破解冷启动 50–500ms 延迟
  • Workbox v7:5 策略类 + ExpirationPlugin / CacheableResponsePlugin / BroadcastUpdatePlugin
  • 强制 HTTPS:仅 localhost 例外;scope 默认 SW 脚本目录,Service-Worker-Allowed 扩大
  • 跨域 opaque:status=0,缓存需 statuses: [0, 200]
  • 查找顺序:SW 缓存 → HTTP 缓存 → 网络
  • 完整说明见 入门 / 深度指南

CacheStorage(caches 全局)方法

方法返回值语义
caches.open(name)Promise<Cache>打开/创建命名缓存容器
caches.keys()Promise<string[]>列全部命名缓存名
caches.has(name)Promise<boolean>是否存在该命名缓存
caches.delete(name)Promise<boolean>删整张命名缓存(与 cache.delete 删单条不同)
caches.match(req, opts)Promise<Response | undefined>跨所有命名缓存查第一个命中

Cache 接口方法

方法返回值语义关键点
cache.match(req, opts)Promise<Response | undefined>查第一个命中未命中 resolve undefined,非 reject
cache.matchAll(req, opts)Promise<Response[]>查全部命中返回数组
cache.put(req, res)Promise<void>写入 Request-Response 对Response 用前必须 clone()
cache.add(url)Promise<void>fetch + put 等价失败时 cache 不变
cache.addAll(urls)Promise<void>批量预缓存原子性,任一失败整批 reject
cache.delete(req, opts)Promise<boolean>删单条返回是否删除
cache.keys()Promise<Request[]>列全部 Request用于迭代清理

cache.match 选项

选项默认作用
ignoreSearchfalsetrue 时忽略 URL 查询串(?v=1?v=2 命中同一条)
ignoreMethodfalse默认 POST/PUT/DELETE 不匹配;true 时不区分
ignoreVaryfalsetrue 时跳过 Response 的 Vary 头校验

五大缓存策略对比

策略流程回写缓存失败兜底典型场景
cache-only仅查缓存失败 504离线 app shell
network-only仅网络失败即失败强一致写操作 / 实时数据
cache-first缓存优先,未命中才网络是(首次)走网络哈希命名静态资源(JS/CSS/字体)
network-first网络优先,失败回退缓存缓存兜底HTML / 关键 API
stale-while-revalidate立即返旧 + 后台更新等网络头像 / 字体 / 非关键图

Workbox v7 策略类

等价策略常用插件
CacheFirstcache-firstExpirationPlugin + CacheableResponsePlugin
NetworkFirstnetwork-firstNetworkFirst({ networkTimeoutSeconds: 3 })
StaleWhileRevalidateSWRExpirationPlugin
CacheOnlycache-only用于已预缓存资源
NetworkOnlynetwork-onlyBroadcastUpdatePlugin 提示更新

Workbox 关键插件

插件作用关键参数
ExpirationPlugin自动淘汰过期/超量条目maxEntries / maxAgeSeconds / purgeOnQuotaError
CacheableResponsePlugin按状态码白名单过滤响应statuses: [0, 200](含 opaque 跨域)
BroadcastUpdatePlugin缓存更新时通知所有页面channelName / headersToCheck
BackgroundSyncPlugin失败请求入队、网络恢复后重试maxRetentionTime / onSync

SW 生命周期阶段

阶段触发常用操作
install首次注册或脚本字节变化event.waitUntil(caches.addAll(...)) 预缓存
waiting有旧 SW 活跃时默认等待旧页面关闭;self.skipWaiting() 立即跳过
activate旧 SW 退场后event.waitUntil(caches.delete 旧版本) + clients.claim()
controlledactivate 完成开始拦截 fetch 事件

事件 API 速查

API用途
ExtendableEvent.waitUntil(promise)install / activate 时延长 SW 存活直到 Promise resolve
FetchEvent.respondWith(promise)fetch 劫持响应,必须 resolve 一个 Response 对象
FetchEvent.preloadResponse导航预加载结果的 Promise(未启用时 resolve undefined

request 分流属性

属性取值用途
request.modenavigate / same-origin / cors / no-corsnavigate 区分 HTML 文档
request.destinationimage / style / script / font / document / ...比文件后缀更可靠
request.methodGET / POST / ...仅缓存 GET
request.urlURL 字符串路由匹配

导航预加载 API

API作用
registration.navigationPreload.enable()启用(activate 里调)
registration.navigationPreload.disable()禁用
registration.navigationPreload.setHeaderValue(value)自定义请求头值(默认 'true'
registration.navigationPreload.getState()查启用状态与头值
event.preloadResponse预加载响应的 Promise(未启用时 resolve undefined

请求头:Service-Worker-Navigation-Preload: true;服务器据此返回不同内容时需配 Vary: Service-Worker-Navigation-Preload

注册与 scope

js
// 注册
if ("serviceWorker" in navigator) {
  navigator.serviceWorker.register("/sw.js", { scope: "/" });
}

// 状态
const reg = await navigator.serviceWorker.ready;
// reg.installing / reg.waiting / reg.active
取值
scope 默认值SW 脚本所在目录
扩大 scope服务器响应 Service-Worker-Allowed: /
HTTPS 强制localhost / 127.0.0.1 例外
跨域脚本crossorigin + CORS 允许
注销registration.unregister()

配额与清理

js
// 查配额
if (navigator.storage && navigator.storage.estimate) {
  const { usage, quota } = await navigator.storage.estimate();
  console.log(`${usage} / ${quota} bytes (${((usage / quota) * 100).toFixed(1)}%)`);
}
行为触发
配额超限浏览器整体清除该 origin 所有缓存(含当前版本)
purgeOnQuotaError: trueExpirationPlugin 在配额超限时才清理(保守策略)
LRU 淘汰ExpirationPlugin 按时间 + 条数自动淘汰

跨域 opaque 响应特征

特征
status0(不是真实状态码)
headers不可读(get(...) 永远返回 null
body不可读(但可整体缓存)
缓存白名单必须 statuses: [0, 200]

版本与运行环境

取值
Cache APIBaseline widely available(2018-04 起)
Service Worker API全主流浏览器默认启用(Chrome/Firefox/Edge/Safari)
NavigationPreloadManager三大浏览器引擎均已支持
Workbox 稳定版v7
HTTPS 要求强制(仅 localhost 例外)
题库基准时间2026

官方资源