service worker注册失败时navigator.serviceworker为undefined,主因是页面未通过https或localhost访问;缓存html读旧版因浏览器默认不触发fetch拦截,须显式监听document请求并实现缓存回退逻辑。

Service Worker 注册失败时为什么 navigator.serviceWorker 返回 undefined
常见现象是页面加载后调用 navigator.serviceWorker.register() 报错,或直接提示 navigator.serviceWorker is undefined。根本原因只有两个:当前环境不支持(如 HTTP 协议下、非 localhost 的非 HTTPS 页面),或浏览器本身禁用了 Service Worker(如某些隐私模式、旧版 Safari)。必须确保页面通过 https:// 或 http://localhost 访问;Safari 16.4+ 才支持 skipWaiting() 和 clients.claim(),老版本会静默忽略。
缓存 HTML 文件时为什么总是读到旧版本
HTML 不会被默认加入缓存策略——即使你在 install 事件里缓存了 /index.html,后续访问仍可能走网络,因为浏览器对 HTML 的请求默认使用 no-cache 或 default 模式,不会主动查 Service Worker 的 fetch 事件。必须显式拦截所有 GET 请求,并对 text/html 类型做优先缓存回退逻辑:
self.addEventListener('fetch', event => {
if (event.request.destination === 'document') {
event.respondWith(
caches.match(event.request)
.then(resp => resp || fetch(event.request))
);
}
});
注意:不要在 install 阶段缓存动态 HTML(如含时间戳的编辑器首页),否则每次更新都要手动 bump 缓存名;建议只缓存静态骨架页,内容由 JS 在线加载或从 IndexedDB 读取。
编辑器资源(CSS/JS/WASM)离线后无法热更新
Service Worker 的缓存是“快照式”的,caches.open('v1') 创建的缓存不会自动感知文件变更。要支持编辑器热更新,需做到三件事:
如果你了解HTML,CSS和JavaScript,您已经拥有所需的工具开发Android应用程序。本动手本书展示了如何使用这些开源web标准设计和建造,可适应任何Android设备的应用程序 - 无需使用Java。您将学习如何创建一个在您选择的平台的Android友好的网络应用程序,然后转换与自由PhoneGap框架到一个原生的Android应用程序。了解为什么设备无关的移动应用是未来的潮流,并开始构建应用程序,提供更
- 每次发布新版本时,把缓存名从
v1改成v2,并在install中预缓存新资源 - 在
activate事件中调用caches.delete('v1')清理旧缓存 - 在客户端检测到新 Service Worker 等待激活时,调用
waiting.postMessage({type: 'SKIP_WAITING'})并监听controllerchange事件触发重载
特别注意:WASM 模块(如 monaco-editor 的语法分析器)必须和 JS 一起被缓存,否则离线时 WebAssembly.instantiateStreaming 会因找不到响应体而抛 TypeError: Failed to execute 'arrayBuffer' on 'Response': body stream already read。
本地开发时 workbox 的 generateSW 为何不生效
Workbox 的 generateSW 默认跳过 localhost 下的非 HTTPS 请求,且要求构建产物路径与 swSrc 中声明的 globPatterns 完全匹配。常见错误包括:
-
globPatterns: ['**/*.js']匹配不到dist/editor.7f3a.js—— 因为 Webpack/Vite 输出的 hash 文件名未被 glob 覆盖,应改用['*.js', 'editor.*.js'] -
swDest设为dist/sw.js,但 HTML 中注册的是/sw.js,导致 404;必须保证路径可被根目录直接访问 - 使用 Vite 开发服务器时,
workbox.generateSW()不会自动注入register()脚本,需手动在index.html底部加:<script> if ('serviceWorker' in navigator) { navigator.serviceWorker.register('/sw.js'); } </script>
真实项目里,比 Workbox 更轻量的做法是手写 50 行以内的 sw.js:只缓存明确路径的 editor 核心资源,避免正则匹配引入不确定性。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!










