PWA离线可用的关键是构建可控、分层、可更新的缓存体系:需HTTPS(或localhost)前提,按安装(预缓存Shell)、运行时(导航/HTML兜底、API用Stale-While-Revalidate、资源Cache First)、更新(skipWaiting+清理旧缓存)四环节设计。

要让 PWA 真正离线可用,关键不是注册一个 Service Worker,而是用它建立可控、分层、可更新的缓存体系。HTTPS(或 localhost)是前提,之后围绕安装、缓存、兜底、更新四个环节设计逻辑。
注册与作用域控制
Service Worker 必须在页面加载后通过 JavaScript 注册,且路径需为根相对路径,确保最大作用域:
- 在 main.js 或 HTML 的 script 标签中写:navigator.serviceWorker.register('/sw.js')
- 路径不能是 ./sw.js 或 /js/sw.js,否则只对子路径生效
- 本地开发用 localhost 可跳过 HTTPS 限制;上线必须部署在 HTTPS 环境
预缓存核心 Shell 资源
安装阶段缓存的是“应用外壳”——用户首次访问时必须呈现的内容,比如首页 HTML、主 CSS/JS、图标等:
- 在 install 事件中调用 caches.open().then(cache => cache.addAll([...]))
- 列表里包含 /index.html、/manifest.json、/offline.html 等静态资产
- 务必包裹 event.waitUntil(),防止安装中途退出导致缓存不全
运行时按需缓存 + 智能兜底
fetch 事件是 Service Worker 的核心执行点,需区分请求类型做不同处理:
- 对导航请求(request.destination === 'document'):优先返回缓存 HTML;未命中则返回预置的 offline.html
- 对 API 请求:推荐 Stale-While-Revalidate 模式——先返回缓存数据,后台静默刷新,兼顾速度与新鲜度
- 对图片、字体等大资源:用 Cache First,减少重复下载
- 避免直接缓存 HTML 页面(除非纯静态),否则用户可能长期看不到更新
更新机制与调试要点
Service Worker 不会自动更新,需主动触发并确保新版本接管:
- 每次修改 sw.js 文件内容(哪怕加个空格),浏览器才会检测到新版本
- 在 install 阶段调用 self.skipWaiting(),跳过 waiting 状态,让新 SW 立即激活
- 在 activate 阶段清理旧缓存:caches.keys().then(keys => Promise.all(keys.map(caches.delete)))
- Chrome DevTools → Application → Service Workers 中勾选 Update on reload,方便开发时即时测试










