最新下载
热门教程
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
如何用 Service Worker 实现离线即走的静态资源静默更新策略
时间:2026-07-19 10:49:59 编辑:袖梨 来源:一聚教程网
“离线即走”要求Service Worker在install阶段用event.waitUntil()预缓存根路径下的核心静态资源(HTML/CSS/JS/图标),版本号随构建变更,配合skipWaiting()和clients.claim()立即接管页面;fetch阶段对静态资源严格Cache First、零网络兜底,确保无网时秒开UI且联网后静默更新。
“离线即走”不是指关掉网络就闪退,而是用户在无网或弱网时打开页面,仍能立刻渲染出完整 UI,且后续联网后自动静默更新缓存——不打断当前操作、不弹提示、不重载页面。这要求 Service Worker 在 install/activate 阶段完成资源预取与版本切换,同时 fetch 阶段对静态资源严格走 Cache First,并用 skipWaiting() 和 clients.claim() 消除旧 worker 占据导致的延迟接管。
install 阶段必须调用 event.waitUntil() + caches.open().addAll()
这是静默更新的前提:所有核心静态资源(HTML、CSS、JS、关键图标)必须在 install 时一次性写入新缓存,不能留到 fetch 时懒加载。否则首次离线访问会失败。
-
caches.open('static-v2')中的版本号(如v2)必须随每次构建变更,否则浏览器认为无更新,跳过 install -
addAll()的路径列表需绝对准确;相对路径(如./main.js)在 SW 环境中会解析失败,一律用根路径(/main.js) - 务必在
addAll()后接self.skipWaiting(),否则新 worker 会卡在 waiting 状态,直到所有页面关闭
activate 阶段要清理旧缓存 + 调用 clients.claim()
旧缓存不清理会占用空间,更严重的是:若旧缓存名(如 static-v1)还存在,而 fetch 逻辑又没做版本判断,就可能误读过期资源。
-
caches.keys()获取全部缓存名,用.filter(name => !name.startsWith('static-v'))或白名单比对,只保留当前版本 -
caches.delete()是异步操作,必须包进event.waitUntil(),否则清理可能被中断 -
self.clients.claim()让新 worker 立即接管当前页(包括已打开但未注册 SW 的 tab),这是“离线即走”不闪屏的关键
fetch 事件里对静态资源强制 Cache First,且禁止 fallback 到 network
所谓“静默”,就是用户完全感知不到缓存行为。一旦在 fetch 中写了 || fetch(request) 这类兜底逻辑,断网时就会触发 fetch 失败,进而抛错或降级——这不是静默,是暴露问题。
- 只对明确匹配静态后缀的请求启用该策略:
request.url.match(/.(js|css|html|png|svg|woff2)$/i) - 响应必须来自
caches.match(request),且不做任何fetch()尝试;如果 match 返回undefined,直接return new Response('', { status: 404 })或返回预置 offline 页面 - 避免在 match 前做
request.clone()—— clone 会消耗 stream,导致后续 fetch 无法读 body
构建流程必须生成内容哈希并注入 SW 脚本
光靠版本号(static-v2)不够。如果文件内容没变但版本号变了,会导致无效缓存;如果内容变了但版本号没变,又会命中旧缓存。真正可靠的依据是文件内容哈希。
- Webpack/Vite 构建时启用
contenthash,生成类似main.a1b2c3d4.js的文件名 - 把哈希化后的资源列表(非通配符)写入 SW 脚本,例如通过
injectManifest插件或构建后替换模板中的ASSETS_TO_CACHE - 不要用
cache.addAll(['/'])这种方式——它依赖服务器配置,且无法控制缓存粒度
最容易被忽略的点:Service Worker 的作用域(scope)默认是 sw.js 所在路径。如果 sw.js 放在 /assets/sw.js,那它只能控制 /assets/ 下的请求。要把 sw.js 放在根目录,并在注册时显式指定 { scope: '/' },否则 HTML 文件本身都缓存不了,“离线即走”就成空谈。
相关文章
- Debian挂载设备后自动卸载如何办 07-31
- Debian挂载命令格式是什么 07-31
- Debian挂载点设置错误如何办 07-31
- Debian挂载ext4分区详细说明 07-31
- 空洞骑士丝之歌猎者小径如何全收集 07-31
- ubuntu gimp如何保存项目文件 07-31