题目
PWA 中如何设计 Service Worker 缓存策略实现离线优先体验?
信息
- 类型:问答
- 难度:⭐⭐
考点
Service Worker 缓存策略,离线体验优化,缓存更新机制
快速回答
实现离线优先体验的核心要点:
- 缓存策略选择:根据资源类型使用
CacheFirst(静态资源)和NetworkFirst(动态内容)策略 - 预缓存关键资源:在 Service Worker
install阶段缓存核心静态文件 - 动态缓存机制:在
fetch事件中按策略处理请求 - 缓存版本控制:通过更改缓存名称强制更新缓存
- 离线回退方案:提供自定义离线页面和备用内容
一、核心原理说明
Service Worker 作为独立线程可拦截网络请求,配合 Cache API 实现:
- 离线优先:优先从缓存返回响应,无缓存时回退网络
- 缓存策略:根据资源类型选择不同策略(如图)

- 更新机制:通过修改缓存名称触发更新,清理旧缓存
二、代码实现示例
1. 注册 Service Worker
// main.js
if ('serviceWorker' in navigator) {
navigator.serviceWorker.register('/sw.js')
.then(reg => console.log('SW registered'))
}2. 预缓存关键资源 (sw.js)
const CACHE_NAME = 'v1-core-assets';
const PRE_CACHE = [
'/',
'/styles/main.css',
'/scripts/app.js',
'/offline.html'
];
self.addEventListener('install', event => {
event.waitUntil(
caches.open(CACHE_NAME)
.then(cache => cache.addAll(PRE_CACHE))
);
});3. 缓存策略实现 (sw.js)
// 网络优先(适合频繁更新的内容)
const networkFirst = async (request) => {
try {
const networkResponse = await fetch(request);
const cache = await caches.open('dynamic-cache');
cache.put(request, networkResponse.clone());
return networkResponse;
} catch {
return caches.match(request) || caches.match('/offline.html');
}
};
// 缓存优先(适合静态资源)
const cacheFirst = async (request) => {
const cachedResponse = await caches.match(request);
if (cachedResponse) return cachedResponse;
try {
const networkResponse = await fetch(request);
const cache = await caches.open('static-cache');
cache.put(request, networkResponse.clone());
return networkResponse;
} catch {
return caches.match('/offline.html');
}
};
self.addEventListener('fetch', event => {
const url = new URL(event.request.url);
if (url.pathname.includes('/api/')) {
event.respondWith(networkFirst(event.request));
} else {
event.respondWith(cacheFirst(event.request));
}
});4. 缓存清理与更新
self.addEventListener('activate', event => {
const cacheWhitelist = ['v2-core-assets'];
event.waitUntil(
caches.keys().then(cacheNames => {
return Promise.all(
cacheNames.map(cacheName => {
if (!cacheWhitelist.includes(cacheName)) {
return caches.delete(cacheName); // 删除旧缓存
}
})
);
})
);
});三、最佳实践
- 策略选择:
- CSS/JS/图片:Cache First + 内容哈希
- API 数据:Network First + 短时间缓存
- HTML 文件:Network First(确保内容更新)
- 缓存限制:设置缓存数量/大小上限,避免存储膨胀
- 更新提示:检测 Service Worker 更新后提示用户刷新
- 降级方案:使用
navigator.onLine检测网络状态
四、常见错误
- 缓存策略错配:对动态内容使用 Cache First 导致数据过期
- 缓存爆炸:未设置缓存上限导致存储空间耗尽
- 版本控制缺失:未更新缓存名称导致用户获取旧资源
- 作用域错误:Service Worker 文件未放在根目录导致无法拦截全部请求
- 忽略 HTTPS:生产环境未使用 HTTPS 导致 Service Worker 无法注册
五、扩展知识
- Workbox 工具库:简化缓存策略配置
import { registerRoute } from 'workbox-routing'; import { CacheFirst, NetworkFirst } from 'workbox-strategies'; registerRoute( ({request}) => request.destination === 'image', new CacheFirst() ); - 后台同步:使用
SyncManager实现离线操作队列 - 推送通知:
Push API+Notification API增强用户粘性 - 性能优化:结合
Lighthouse审计 PWA 核心指标(速度指数、可交互时间)