前端缓存方式对比表和Service Worker缓存详细讲解
作者:前端开发_穆金秋
前端缓存方式对比表
| 缓存方式 | 工作机制 | 优势 | 劣势 | 适用场景 |
|---|---|---|---|---|
| HTTP缓存 | 通过HTTP头控制缓存策略 | 1. 浏览器自动管理 2. 减少网络请求 3. 强缓存零延迟 | 1. 需服务器配置 2. 缓存更新需策略控制 | 静态资源(CSS/JS/图片) |
| • 强缓存 (Expires/Cache-Control) | 直接使用本地副本,不发请求 | 响应最快,零网络开销 | 更新不及时,需版本控制 | 版本化静态资源 |
| • 协商缓存 (Last-Modified/Etag) | 向服务器验证资源是否更新 | 保证资源最新 节省带宽 | 仍有请求延迟 需服务器计算标识 | 频繁更新的资源 |
| Service Worker缓存 | 拦截请求,可编程控制缓存 | 1. 离线可用 2. 细粒度控制 3. 可结合多种策略 | 1. 实现复杂 2. 需HTTPS 3. 首次需注册 | PWA、离线应用、复杂缓存策略 |
| Web Storage (Local/Session Storage) | 键值对存储,同源策略 | 1. 存储量大(5-10MB) 2. API简单 3. 同标签页共享 | 1. 同步操作 2. 仅字符串 3. 无自动过期 | 用户偏好、表单数据、非敏感信息 |
| IndexedDB | 浏览器中的NoSQL数据库 | 1. 大容量(>250MB) 2. 事务支持 3. 复杂查询 | 1. API复杂 2. 异步操作 3. 学习成本高 | 大型结构化数据、离线数据 |
| Cookie | 随请求自动发送到服务器 | 1. 自动管理 2. 服务端可读 3. 有过期机制 | 1. 容量小(4KB) 2. 性能开销 3. 安全性需注意 | 会话管理、身份认证 |
| 应用缓存 (Application Cache) | 通过manifest文件声明缓存 | 1. 简单配置 2. 离线可用 | 1. 已废弃 2. 更新机制差 3. 调试困难 | 不推荐使用,用Service Worker替代 |
缓存策略选择建议
按资源类型选择:
静态资源(版本固定):强缓存 + 文件名哈希
静态资源(频繁更新):协商缓存
API数据:Service Worker + 网络优先/缓存备用策略
用户数据:Web Storage(小量)、IndexedDB(大量)
会话数据:Session Storage / Cookie
性能优化组合:
静态资源:
Cache-Control: max-age=31536000(一年)+ 文件名哈希动态内容:
Cache-Control: no-cache+ ETag验证离线应用:Service Worker(Cache API + 回退策略)
状态持久化:Redux/Pinia + Web Storage持久化插件
注意事项:
缓存污染:合理设置缓存键,避免数据混淆
内存管理:定期清理过期缓存(特别是Cache API)
安全:敏感数据避免存储在LocalStorage
版本控制:静态资源使用内容哈希,避免更新问题
缓存更新策略示例
javascript
// Service Worker 缓存策略:网络优先,失败用缓存
self.addEventListener('fetch', event => {
event.respondWith(
fetch(event.request)
.catch(() => caches.match(event.request))
);
});
// 版本化缓存:资源URL带哈希
// style.abc123.css -> 强缓存一年
<link href="/css/style.abc123.css" rel="external nofollow" rel="stylesheet">选择合适的缓存策略需要综合考虑资源类型、更新频率、数据大小和用户体验要求,通常需要组合使用多种缓存方式。
Service Worker 缓存详解
一、Service Worker 基础架构
1.生命周期
注册 → 安装 → 激活 → 监听事件 → 终止
2.核心特性
独立线程:与主线程分离,不阻塞UI
可编程缓存:通过Cache API精细控制
请求拦截:可拦截、修改网络请求
离线支持:网络不可用时仍可响应
后台同步:支持后台数据同步
二、Cache API 详解
1.缓存存储结构
// 打开/创建缓存
caches.open('v1').then(cache => {
// cache 对象操作
});
// 查看所有缓存
caches.keys().then(keys => {
console.log('所有缓存:', keys);
});2.缓存操作方法
const CACHE_NAME = 'my-cache-v1'; const urlsToCache = [ '/', '/styles/main.css', '/scripts/app.js', '/images/logo.png' ]; // 1. 添加单个资源 cache.put(request, response); // 2. 添加多个资源 cache.addAll(urlsToCache); // 3. 匹配缓存 cache.match(request); // 4. 删除缓存 cache.delete(request); // 5. 获取所有缓存键 cache.keys();
三、常用缓存策略
1.缓存优先(Cache First)
self.addEventListener('fetch', event => {
event.respondWith(
caches.match(event.request)
.then(response => {
// 有缓存直接返回
if (response) {
return response;
}
// 否则从网络获取
return fetch(event.request)
.then(response => {
// 可选:缓存新资源
return caches.open(CACHE_NAME)
.then(cache => {
cache.put(event.request, response.clone());
return response;
});
});
})
);
});2.网络优先(Network First)
self.addEventListener('fetch', event => {
event.respondWith(
fetch(event.request)
.then(response => {
// 网络成功:更新缓存
return caches.open(CACHE_NAME)
.then(cache => {
cache.put(event.request, response.clone());
return response;
});
})
.catch(() => {
// 网络失败:使用缓存
return caches.match(event.request);
})
);
});3.仅缓存(Cache Only)
self.addEventListener('fetch', event => {
event.respondWith(
caches.match(event.request)
.then(response => {
if (!response) {
// 没有缓存时返回兜底页面
return caches.match('/offline.html');
}
return response;
})
);
});4.仅网络(Network Only)
self.addEventListener('fetch', event => {
event.respondWith(fetch(event.request));
});5.Stale-While-Revalidate(先旧后新)
self.addEventListener('fetch', event => {
event.respondWith(
caches.open(CACHE_NAME).then(cache => {
return cache.match(event.request).then(cachedResponse => {
const fetchPromise = fetch(event.request).then(networkResponse => {
// 更新缓存
cache.put(event.request, networkResponse.clone());
return networkResponse;
});
// 优先返回缓存,同时更新缓存
return cachedResponse || fetchPromise;
});
})
);
});6.运行时缓存(Runtime Caching)
// 动态决定缓存策略
self.addEventListener('fetch', event => {
const url = new URL(event.request.url);
// API请求:网络优先
if (url.pathname.startsWith('/api/')) {
return networkFirstStrategy(event);
}
// 静态资源:缓存优先
if (url.pathname.startsWith('/static/')) {
return cacheFirstStrategy(event);
}
// 其他:默认策略
return defaultStrategy(event);
});四、高级缓存模式
1.版本化缓存管理
const CACHE_VERSION = 'v2';
const CACHE_NAME = `app-cache-${CACHE_VERSION}`;
const OLD_CACHES = ['app-cache-v1'];
// 安装时:缓存关键资源
self.addEventListener('install', event => {
event.waitUntil(
caches.open(CACHE_NAME)
.then(cache => cache.addAll(criticalResources))
.then(() => self.skipWaiting()) // 立即激活
);
});
// 激活时:清理旧缓存
self.addEventListener('activate', event => {
event.waitUntil(
caches.keys().then(cacheNames => {
return Promise.all(
cacheNames.map(cacheName => {
if (OLD_CACHES.includes(cacheName)) {
return caches.delete(cacheName);
}
})
);
}).then(() => self.clients.claim()) // 控制所有客户端
);
});2.缓存过期策略
// 定期清理过期缓存
self.addEventListener('activate', event => {
event.waitUntil(
caches.open(CACHE_NAME).then(cache => {
return cache.keys().then(requests => {
return Promise.all(
requests.map(request => {
return cache.match(request).then(response => {
if (!response) return null;
// 检查缓存时间
const cachedDate = new Date(response.headers.get('date'));
const now = new Date();
const cacheAge = now - cachedDate;
// 超过7天删除
if (cacheAge > 7 * 24 * 60 * 60 * 1000) {
return cache.delete(request);
}
return null;
});
})
);
});
})
);
});3.请求预缓存
// 预缓存可能访问的资源
self.addEventListener('install', event => {
event.waitUntil(
caches.open(CACHE_NAME).then(cache => {
// 缓存当前页面资源
return cache.addAll(currentPageResources);
}).then(() => {
// 预加载其他页面资源(不阻塞安装)
self.skipWaiting();
return preloadFutureResources();
})
);
});
function preloadFutureResources() {
return fetch('/api/predict-resources')
.then(res => res.json())
.then(resources => {
return caches.open(CACHE_NAME)
.then(cache => cache.addAll(resources));
})
.catch(err => console.log('预加载失败:', err));
}4.响应定制与降级
self.addEventListener('fetch', event => {
event.respondWith(
caches.match(event.request)
.then(response => {
if (response) return response;
return fetch(event.request)
.then(networkResponse => {
// 只缓存成功的响应
if (networkResponse.ok) {
const clonedResponse = networkResponse.clone();
caches.open(CACHE_NAME)
.then(cache => cache.put(event.request, clonedResponse));
}
return networkResponse;
})
.catch(error => {
// 根据请求类型返回不同降级内容
const request = event.request;
if (request.headers.get('Accept').includes('text/html')) {
return caches.match('/offline.html');
}
if (request.headers.get('Accept').includes('image')) {
return caches.match('/images/placeholder.jpg');
}
return new Response('网络不可用', {
status: 503,
headers: { 'Content-Type': 'text/plain' }
});
});
})
);
});5.智能缓存策略
class SmartCache {
constructor() {
this.config = {
maxSize: 50 * 1024 * 1024, // 50MB
ttl: {
html: 5 * 60 * 1000, // 5分钟
api: 60 * 1000, // 1分钟
image: 7 * 24 * 60 * 60 * 1000 // 7天
}
};
}
async shouldCache(request, response) {
const url = new URL(request.url);
// 不缓存非GET请求
if (request.method !== 'GET') return false;
// 不缓存API错误响应
if (!response.ok) return false;
// 不缓存大文件(>10MB)
const contentLength = response.headers.get('content-length');
if (contentLength > 10 * 1024 * 1024) return false;
return true;
}
}五、性能优化技巧
1.缓存分层策略
// 多级缓存:内存 + Service Worker + HTTP
class LayeredCache {
constructor() {
this.cacheLevels = {
memory: new Map(), // 内存缓存(会话级)
sw: CACHE_NAME, // Service Worker缓存
http: null // HTTP缓存(浏览器控制)
};
}
async get(request) {
// 1. 先查内存缓存
const memoryKey = request.url;
if (this.cacheLevels.memory.has(memoryKey)) {
return this.cacheLevels.memory.get(memoryKey);
}
// 2. 再查Service Worker缓存
const swCache = await caches.open(this.cacheLevels.sw);
const swResponse = await swCache.match(request);
if (swResponse) {
// 存入内存缓存
this.cacheLevels.memory.set(memoryKey, swResponse.clone());
return swResponse;
}
// 3. 最后走网络(HTTP缓存会生效)
return fetch(request);
}
}2.缓存预热
// 空闲时预加载资源
self.addEventListener('message', event => {
if (event.data.type === 'PRELOAD_RESOURCES') {
event.waitUntil(
preloadResources(event.data.urls)
);
}
});
function preloadResources(urls) {
return Promise.all(
urls.map(url => {
return fetch(url)
.then(response => {
if (response.ok) {
return caches.open(CACHE_NAME)
.then(cache => cache.put(url, response));
}
})
.catch(() => {/* 静默失败 */});
})
);
}六、调试与监控
1.调试工具
// Service Worker调试日志
self.addEventListener('fetch', event => {
console.log(`[SW] Fetch: ${event.request.url}`);
console.log(`[SW] Mode: ${event.request.mode}`);
console.log(`[SW] Cache: ${caches.keys()}`);
});2.缓存状态监控
// 监控缓存使用情况
async function getCacheStats() {
const cache = await caches.open(CACHE_NAME);
const requests = await cache.keys();
let totalSize = 0;
const stats = await Promise.all(
requests.map(async request => {
const response = await cache.match(request);
const contentLength = response.headers.get('content-length');
return {
url: request.url,
size: parseInt(contentLength || 0),
type: response.headers.get('content-type')
};
})
);
totalSize = stats.reduce((sum, item) => sum + item.size, 0);
return {
totalItems: stats.length,
totalSize,
items: stats
};
}七、最佳实践
推荐做法
资源分类:不同资源类型使用不同策略
版本控制:每次更新使用新缓存名称
渐进增强:缓存作为性能优化,不是必需功能
监控告警:监控缓存命中率和错误率
容量控制:定期清理过期缓存
注意事项
HTTPS要求:生产环境必须使用HTTPS
缓存污染:避免缓存个性化内容
内存泄漏:定期清理无用缓存
更新策略:明确缓存失效机制
回退方案:网络和缓存都失败时的处理
策略选择指南
| 场景 | 推荐策略 | 理由 |
|---|---|---|
| 静态资源(版本化) | 缓存优先 + 长期缓存 | 内容不变,性能最优 |
| API数据(实时性高) | 网络优先 | 保证数据最新 |
| 用户生成内容 | Stale-While-Revalidate | 平衡速度与新鲜度 |
| 离线应用 | 缓存优先 + 降级页面 | 保证基本功能可用 |
| 大文件(视频/图片) | 按需缓存 + 容量控制 | 避免存储空间占用过大 |
Service Worker缓存是现代Web应用性能优化的核心工具,合理使用可以显著提升用户体验,特别是在弱网和离线场景下。
总结
到此这篇关于前端缓存方式对比表和Service Worker缓存详细讲解的文章就介绍到这了,更多相关前端缓存方式和Service Worker缓存内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!
