线上白屏主因是 activate 阶段未彻底清除旧缓存,导致 caches.match() 返回过期或空 html;须在 activate 中用 caches.keys() 匹配并 delete 旧缓存,配合 event.waituntil(),fetch 时严格限定缓存名与匹配策略,并通过 skipwaiting() 和 controllerchange 主动刷新,服务端禁缓存 sw.js,多浏览器需针对性清理。

线上白屏不是没缓存,而是旧缓存还活着,新 Service Worker 拦不住它——关键在 activate 阶段没清干净。
必须在 activate 阶段彻底清理旧缓存
install 阶段装新缓存,activate 阶段才真正“交班”。若跳过清理,旧缓存(比如 cache-v1)仍会被 caches.match() 命中,返回过期 HTML 或空响应,直接白屏。
- 在
self.addEventListener('activate', event => { ... })中调用caches.keys(),遍历所有缓存名 - 用正则匹配旧命名规则(如
/^cache-\d+$/或cache-v1),对非当前版本缓存调用caches.delete() -
务必加
event.waitUntil(),确保清理完成再进入激活状态
fetch 里别让旧缓存“钻空子”
即使 activate 清了旧缓存,如果 fetch 逻辑写得松散,仍可能因 URL 匹配不严而误用残留资源。
- HTML 页面请求(
event.request.destination === 'document')必须走缓存优先,且只匹配当前缓存名,避免 fallback 到已删但未清完的缓存 - 静态资源(JS/CSS)建议用
{ ignoreSearch: true }匹配,防止main.js?v=123和缓存中的main.js不一致导致 miss - 不要写
if (cached) return cached; else return fetch()这种裸 fallback——万一缓存里存的是空 Response,就会白屏
上线前强制打破“waiting 状态”僵局
用户浏览器可能长期没关,旧 SW 一直 waiting,新版本迟迟不生效。需人工干预打破僵局。
- 在新 SW 的
install事件开头加self.skipWaiting(),让新 SW 立即尝试接管 - 在页面 JS 中监听
controllerchange,检测到新 SW 激活后,提示用户刷新(或自动location.reload(true)) - 服务端对
/sw.js响应头加Cache-Control: no-cache,确保每次都能拿到最新脚本
多浏览器要额外防残留
不同浏览器对缓存清理的激进程度不同,尤其火狐会把 Cache Storage 和 AppCache 条目分开存,容易漏清。
- Chrome / Edge:清除 Application → Service Workers + Cache Storage + Clear site data 即可覆盖大部分
- Firefox:需额外检查
about:cache页面,手动清空disk和memory缓存条目 - UC / QQ 浏览器:常保留离线包副本,建议在调试时启用“禁用所有 Service Worker”开关










