Service Worker 是当前唯一可行的离线缓存方案;它通过 JavaScript 拦截 fetch 事件自主控制缓存策略,支持增量更新、多缓存空间管理及清晰的生命周期控制,取代了已废弃且存在严重缺陷的 Application Cache。

不一样。HTML 本身没有原生离线存储机制,所谓“HTML 离线存储”实际是误称;真正提供标准化离线能力的是 HTML5 引入的 Application Cache(已废弃)和后续替代方案 Service Workers。
Application Cache(.manifest)为什么必须淘汰?
它曾是 HTML5 最早定义的离线方案,但设计缺陷明显:
-
CACHE MANIFEST文件一旦有任意字符变动(哪怕只改个注释),浏览器就会强制重新下载所有CACHE:列出的资源——无法增量更新,流量和加载耗时不可控 - 缓存更新逻辑诡异:用户首次访问用旧缓存,第二次访问才生效新版本,且需手动调用
window.applicationCache.swapCache()+location.reload(),体验断裂 - 不支持动态路由、无法拦截非 GET 请求、不兼容 HTTPS 的某些中间件,现代构建工具(如 Vite、Webpack)也完全不生成 .manifest 文件
- Chrome 从 94 版起彻底移除支持,Firefox 和 Safari 更早弃用,2026 年已无实际部署价值
Service Worker 是当前唯一可行的离线缓存方案
它不是“自动缓存”,而是通过 JavaScript 脚本主动拦截 fetch 事件,自行决定哪些请求走网络、哪些读缓存、哪些合成响应:
- 必须在 HTTPS 或
localhost下注册,否则navigator.serviceWorker.register()直接失败 - 缓存策略完全可控:比如
Cache-first(优先读缓存,失效再拉)、Network-first(先试网,失败 fallback 缓存) - 可配合
Cache API精确管理多个缓存空间(如'static-v1'存 JS/CSS,'images-v2'存图片) - 更新逻辑清晰:新 SW 安装后,旧 SW 仍处理当前页面;调用
self.skipWaiting()+clients.claim()可立即接管
self.addEventListener('install', e => {
e.waitUntil(
caches.open('static-v1').then(cache =>
cache.addAll([
'/index.html',
'/app.js',
'/style.css'
])
)
);
});
self.addEventListener('fetch', e => {
e.respondWith(
caches.match(e.request).then(cached => cached || fetch(e.request))
);
});
localStorage/sessionStorage 不是离线存储,别混用
它们属于「本地数据存储」,和「离线缓存资源文件」是两类事:
立即学习“前端免费学习笔记(深入)”;
-
localStorage存的是字符串键值对(哪怕存 JSON,也要JSON.stringify()),最大约 5–10 MB,适合用户偏好、表单草稿等结构简单数据 -
sessionStorage生命周期仅限标签页,关掉就丢,不适合离线场景 - 两者都不参与页面 HTML/CSS/JS 的加载流程——即使你把整个
index.html字符串塞进localStorage,浏览器也不会用它来渲染首屏 - 真正离线可用的,是让浏览器在无网络时仍能发起
GET /index.html并返回有效 HTML 文档,这只能靠 Service Worker 或(已废)Application Cache 实现
现在做离线 Web 应用,Service Worker 是唯一正解;若项目还依赖 .manifest,说明技术栈严重滞后,升级不是可选项,而是必选项。IndexedDB 可搭配使用存业务数据,但别指望它替你缓存 JS 文件。











