Service Worker 是通过 HTTPS 注册的独立后台脚本,用于拦截请求、缓存资源和实现离线访问;注册需同源且建议置于根目录;安装阶段预缓存静态资源并跳过等待;激活时清理旧缓存并接管页面;fetch 事件中实现缓存优先策略,注意 clone 响应流;更新依赖字节对比,可通过 skipWaiting 和 controllerchange 控制生效。

Service Worker 是浏览器提供的后台脚本,能拦截网络请求、缓存资源、实现离线访问。它必须通过 HTTPS(本地 localhost 除外)注册,且生命周期独立于页面。
注册 Service Worker
在页面加载时注册 SW 脚本,通常放在 main.js 或 HTML 的 <script> 中:
if ('serviceWorker' in navigator) {
window.addEventListener('load', () => {
navigator.serviceWorker.register('/sw.js')
.then(reg => console.log('SW registered:', reg.scope))
.catch(err => console.error('SW registration failed:', err));
});
}
注意:sw.js 必须与页面同源,且建议放在站点根目录,否则作用域受限(例如注册在 /assets/sw.js 则只能控制 /assets/ 下的请求)。
安装阶段:预缓存核心资源
在 SW 的 install 事件中,用 caches.open() 创建缓存并添加静态资源(如 HTML、JS、CSS、图标):
立即学习“Java免费学习笔记(深入)”;
const CACHE_NAME = 'v1';
const PRECACHE_URLS = [
'/',
'/index.html',
'/app.js',
'/style.css',
'/logo.png'
];
self.addEventListener('install', event => {
event.waitUntil(
caches.open(CACHE_NAME)
.then(cache => cache.addAll(PRECACHE_URLS))
.then(() => self.skipWaiting())
);
});
关键点:
-
event.waitUntil()确保安装完成后再进入激活态; -
self.skipWaiting()让新 SW 立即激活(跳过 waiting 状态),避免旧 SW 持续占用; - 首次加载时缓存资源,后续更新需手动更新
CACHE_NAME并清理旧缓存。
激活阶段:清理旧缓存
在 activate 事件中删除不再使用的缓存版本,防止缓存堆积:
self.addEventListener('activate', event => {
const validCaches = [CACHE_NAME];
event.waitUntil(
caches.keys().then(keys => {
return Promise.all(
keys.map(key => {
if (!validCaches.includes(key)) {
return caches.delete(key);
}
})
);
}).then(() => self.clients.claim())
);
});
self.clients.claim() 使激活后的 SW 立即接管所有当前页面(包括已打开但未受控的页面)。
拦截请求:缓存优先 + 回退网络
在 fetch 事件中自定义响应逻辑,常用策略是“缓存优先,失败则网络请求”:
self.addEventListener('fetch', event => {
const { request } = event;
// 只拦截 GET 请求(POST 等通常不缓存)
if (request.method !== 'GET') return;
event.respondWith(
caches.match(request).then(cached => {
if (cached) return cached;
return fetch(request).then(response => {
// 对非错误响应做缓存(可选:仅缓存特定状态码或 URL)
if (response.status === 200 && response.type === 'basic') {
const responseToCache = response.clone();
caches.open(CACHE_NAME)
.then(cache => cache.put(request, responseToCache));
}
return response;
});
})
);
});
注意细节:
-
caches.match()匹配请求 URL 和 headers(默认忽略 Vary 头,如需精确匹配可传入{ ignoreVary: true }); -
response.clone()是必须的——因为 Response 流只能读一次; - 动态资源(如 API 接口)建议单独处理,例如使用“网络优先”或“Stale-while-revalidate”策略。
更新 Service Worker
浏览器在页面每次加载时检查 SW 文件是否变化(基于字节对比)。一旦发现新版本,会安装并进入 waiting 状态。要立即启用新版本,可在页面中监听 controllerchange 或调用 skipWaiting(),并在激活后刷新页面:
// 页面中监听 SW 更新
navigator.serviceWorker.addEventListener('controllerchange', () => {
if (confirm('新版本已就绪,是否刷新?')) {
window.location.reload();
}
});
也可在 SW 内部发送消息通知页面更新,更友好地提示用户。


















