Service Worker 中 fetch 事件是资源加载控制核心,支持网络优先、缓存优先、缓存 + 网络并行及动态策略四种模式,需结合 URL、资源类型等条件精准分流。

在 Service Worker 中,fetch 事件是控制资源加载逻辑的核心入口。通过监听它,你可以决定一个请求是走网络、读缓存,还是两者结合(如网络优先 fallback 到缓存,或缓存优先再更新)。关键在于拦截请求后,用 event.respondWith() 主动返回一个 Response 对象。
网络优先:先试网络,失败再用缓存
适合内容更新频繁、强一致性要求高的场景(如用户通知、实时数据)。核心思路是发起网络请求,用 catch 捕获失败,再尝试匹配缓存。
- 调用
fetch(request)发起网络请求 - 成功时直接返回响应;失败时(如离线、超时、跨域拒绝)进入
catch - 在
catch中打开对应缓存,用cache.match(request)查找命中项 - 若缓存存在,返回它;否则返回一个兜底响应(如
new Response('Offline', { status: 503}))
缓存优先:先查缓存,未命中再发网络
适合静态资源或变动不大的内容(如 CSS、JS、图片),能显著降低延迟和服务器压力。注意:它不自动更新缓存,需配合其他策略(如后台静默更新)保持新鲜度。
- 先打开缓存(如
caches.open('v1')),再match(request) - 命中则直接返回缓存响应
- 未命中则调用
fetch(request),并将返回的响应克隆一份写入缓存(cache.put(request, response.clone())),再返回原始响应 - 建议对非 GET 请求或特殊 header 的请求跳过缓存逻辑(避免缓存 POST 或带认证的响应)
缓存 + 网络并行:立即返回缓存,后台更新后刷新页面
兼顾速度与新鲜度,常用于 SPA 的 HTML 页面或关键资源。用户看到的是旧内容,但新内容已在后台拉取并缓存,下次访问即生效;还可触发 UI 提示“有新版本”。
- 先
cache.match(request),若有则立即返回(event.respondWith(cachedResponse)) - 同时发起
fetch(request),成功后将响应存入缓存(cache.put(request, response)) - 可选:通过
clients.matchAll()获取所有打开的页面,并用postMessage通知其刷新 - 注意避免重复写缓存或竞态问题,可用
cache.addAll([……])替代单个put提升可靠性
按资源类型 /URL 动态选择策略
实际项目中很少全局统一策略。应根据请求 URL、method、header 或资源类型(HTML / JSON / image)分流处理。
- 例如:以
/api/开头的请求用网络优先;.css、.js用缓存优先;根路径/用缓存 + 网络并行 - 可用正则或 URL 构造器解析
request.url,或检查request.destination(如'script'、'image') - 对带查询参数的请求(如
?t=123),注意缓存键是否包含参数——通常需规范化(如剔除跟踪类参数)再匹配