前端资源缓存
概述
资源缓存是前端性能优化的核心策略之一,它通过减少网络请求、降低带宽消耗和加速页面加载来提升用户体验。有效的缓存策略可以显著减少重复资源的加载,即使在网络不稳定的情况下也能提供更好的用户体验。
核心概念
1. 缓存类型对比
缓存类型对比:
| 缓存类型 | 存储位置 | 生命周期 | 控制程度 | 适用场景 |
|---|---|---|---|---|
| 浏览器缓存 | 浏览器本地 | 可设置 | 中等 | 静态资源,通用缓存 |
| CDN缓存 | 边缘节点 | 可配置 | 高 | 全球分发,静态资源 |
| Service Worker缓存 | 浏览器本地 | 完全控制 | 最高 | PWA应用,离线功能 |
| 应用层缓存 | 内存/本地存储 | 完全控制 | 最高 | 动态数据,状态管理 |
缓存策略选择决策树:
2. 缓存机制特点
缓存机制特点图示:
技术实现方案
1. 浏览器缓存
强缓存实现:
// 强缓存配置
const setStrongCache = (res, maxAge = 31536000) => {
res.setHeader('Cache-Control', `max-age=${maxAge}, public`);
res.setHeader('Expires', new Date(Date.now() + maxAge * 1000).toUTCString());
};
// 协商缓存实现
const setNegotiationCache = (res, etag, lastModified) => {
res.setHeader('Cache-Control', 'no-cache');
res.setHeader('ETag', etag);
res.setHeader('Last-Modified', lastModified);
};
// 缓存验证中间件
const cacheValidation = (req, res, next) => {
const ifNoneMatch = req.headers['if-none-match'];
const ifModifiedSince = req.headers['if-modified-since'];
// 检查ETag
if (ifNoneMatch && ifNoneMatch === res.getHeader('ETag')) {
return res.status(304).end();
}
// 检查Last-Modified
if (ifModifiedSince && new Date(ifModifiedSince) >= new Date(res.getHeader('Last-Modified'))) {
return res.status(304).end();
}
next();
};
客户端缓存管理:
// 客户端缓存管理器
class BrowserCacheManager {
constructor() {
this.cache = new Map();
this.maxSize = 100;
this.ttl = 300000; // 5分钟
}
// 设置缓存
set(key, value, ttl = this.ttl) {
// 检查缓存大小
if (this.cache.size >= this.maxSize) {
this.cleanup();
}
this.cache.set(key, {
value,
timestamp: Date.now(),
ttl
});
}
// 获取缓存
get(key) {
const item = this.cache.get(key);
if (!item) {
return null;
}
// 检查是否过期
if (Date.now() - item.timestamp > item.ttl) {
this.cache.delete(key);
return null;
}
return item.value;
}
// 删除缓存
delete(key) {
return this.cache.delete(key);
}
// 清理过期缓存
cleanup() {
const now = Date.now();
for (const [key, item] of this.cache.entries()) {
if (now - item.timestamp > item.ttl) {
this.cache.delete(key);
}
}
}
// 清空所有缓存
clear() {
this.cache.clear();
}
}
// 使用示例
const cacheManager = new BrowserCacheManager();
// 设置缓存
cacheManager.set('userData', { name: 'John', age: 30 }, 60000); // 1分钟
// 获取缓存
const userData = cacheManager.get('userData');
console.log('用户数据:', userData);
2. Service Worker缓存
Service Worker缓存实现:
// Service Worker缓存管理器
class ServiceWorkerCacheManager {
constructor(cacheName = 'app-cache-v1') {
this.cacheName = cacheName;
this.strategies = {
cacheFirst: this.cacheFirst.bind(this),
networkFirst: this.networkFirst.bind(this),
staleWhileRevalidate: this.staleWhileRevalidate.bind(this)
};
}
// 缓存优先策略
async cacheFirst(request) {
const cachedResponse = await caches.match(request);
if (cachedResponse) {
return cachedResponse;
}
const networkResponse = await fetch(request);
const cache = await caches.open(this.cacheName);
cache.put(request, networkResponse.clone());
return networkResponse;
}
// 网络优先策略
async networkFirst(request) {
try {
const networkResponse = await fetch(request);
const cache = await caches.open(this.cacheName);
cache.put(request, networkResponse.clone());
return networkResponse;
} catch (error) {
const cachedResponse = await caches.match(request);
return cachedResponse || new Response('Network error', { status: 408 });
}
}
// Stale-While-Revalidate策略
async staleWhileRevalidate(request) {
const cache = await caches.open(this.cacheName);
const cachedResponse = await cache.match(request);
// 异步更新缓存
const fetchPromise = fetch(request).then(networkResponse => {
cache.put(request, networkResponse.clone());
return networkResponse;
});
// 返回缓存响应(如果存在)或等待网络响应
return cachedResponse || await fetchPromise;
}
// 预缓存资源
async precache(urls) {
const cache = await caches.open(this.cacheName);
return await cache.addAll(urls);
}
// 清理旧缓存
async cleanup() {
const cacheNames = await caches.keys();
const oldCaches = cacheNames.filter(name => name !== this.cacheName);
return await Promise.all(
oldCaches.map(name => caches.delete(name))
);
}
}
// Service Worker注册
if ('serviceWorker' in navigator) {
navigator.serviceWorker.register('/sw.js')
.then(registration => {
console.log('Service Worker注册成功');
})
.catch(error => {
console.error('Service Worker注册失败:', error);
});
}
// Service Worker文件 (sw.js)
const cacheManager = new ServiceWorkerCacheManager('my-app-cache-v1');
// 安装事件
self.addEventListener('install', event => {
event.waitUntil(
cacheManager.precache([
'/',
'/index.html',
'/styles.css',
'/app.js',
'/images/logo.png'
])
);
});
// 激活事件
self.addEventListener('activate', event => {
event.waitUntil(cacheManager.cleanup());
});
// 获取事件
self.addEventListener('fetch', event => {
const { request } = event;
// 根据请求类型选择策略
if (request.url.includes('/api/')) {
event.respondWith(cacheManager.strategies.networkFirst(request));
} else if (request.url.includes('/static/')) {
event.respondWith(cacheManager.strategies.cacheFirst(request));
} else {
event.respondWith(cacheManager.strategies.staleWhileRevalidate(request));
}
});
3. 应用层缓存
应用层缓存实现:
// 应用层缓存管理器
class ApplicationCacheManager {
constructor(options = {}) {
this.cache = new Map();
this.maxSize = options.maxSize || 1000;
this.ttl = options.ttl || 300000; // 5分钟
this.storage = options.storage || localStorage;
this.persistent = options.persistent || false;
}
// 设置缓存
async set(key, value, options = {}) {
const { ttl = this.ttl, persistent = this.persistent } = options;
const cacheItem = {
value,
timestamp: Date.now(),
ttl,
persistent
};
// 内存缓存
this.cache.set(key, cacheItem);
// 持久化缓存
if (persistent) {
try {
this.storage.setItem(key, JSON.stringify(cacheItem));
} catch (error) {
console.error('持久化缓存失败:', error);
}
}
}
// 获取缓存
async get(key) {
// 先从内存获取
let item = this.cache.get(key);
// 如果内存中没有且支持持久化,从存储获取
if (!item && this.persistent) {
try {
const stored = this.storage.getItem(key);
if (stored) {
item = JSON.parse(stored);
this.cache.set(key, item);
}
} catch (error) {
console.error('获取持久化缓存失败:', error);
}
}
if (!item) {
return null;
}
// 检查是否过期
if (Date.now() - item.timestamp > item.ttl) {
this.delete(key);
return null;
}
return item.value;
}
// 删除缓存
delete(key) {
this.cache.delete(key);
if (this.persistent) {
try {
this.storage.removeItem(key);
} catch (error) {
console.error('删除持久化缓存失败:', error);
}
}
}
// 清理过期缓存
cleanup() {
const now = Date.now();
for (const [key, item] of this.cache.entries()) {
if (now - item.timestamp > item.ttl) {
this.delete(key);
}
}
}
// 清空所有缓存
clear() {
this.cache.clear();
if (this.persistent) {
try {
this.storage.clear();
} catch (error) {
console.error('清空持久化缓存失败:', error);
}
}
}
// 获取缓存统计
getStats() {
return {
size: this.cache.size,
maxSize: this.maxSize,
memoryUsage: this.cache.size * 100, // 估算
persistent: this.persistent
};
}
}
// 使用示例
const appCache = new ApplicationCacheManager({
maxSize: 500,
ttl: 600000, // 10分钟
persistent: true
});
// 设置缓存
await appCache.set('userProfile', { name: 'John', age: 30 }, {
ttl: 300000, // 5分钟
persistent: true
});
// 获取缓存
const userProfile = await appCache.get('userProfile');
console.log('用户资料:', userProfile);
// 获取统计信息
const stats = appCache.getStats();
console.log('缓存统计:', stats);
4. 缓存策略实现
缓存策略管理器:
// 缓存策略管理器
class CacheStrategyManager {
constructor() {
this.strategies = new Map();
this.defaultStrategy = 'cacheFirst';
}
// 注册策略
registerStrategy(name, strategy) {
this.strategies.set(name, strategy);
}
// 获取策略
getStrategy(name) {
return this.strategies.get(name) || this.strategies.get(this.defaultStrategy);
}
// 执行策略
async executeStrategy(name, request, options = {}) {
const strategy = this.getStrategy(name);
if (!strategy) {
throw new Error(`策略 ${name} 不存在`);
}
return await strategy(request, options);
}
}
// 缓存策略实现
const cacheStrategies = {
// 缓存优先
cacheFirst: async (request, options) => {
const { cache, network } = options;
try {
const cachedResponse = await cache.match(request);
if (cachedResponse) {
return cachedResponse;
}
const networkResponse = await network.fetch(request);
await cache.put(request, networkResponse.clone());
return networkResponse;
} catch (error) {
console.error('缓存优先策略失败:', error);
throw error;
}
},
// 网络优先
networkFirst: async (request, options) => {
const { cache, network } = options;
try {
const networkResponse = await network.fetch(request);
await cache.put(request, networkResponse.clone());
return networkResponse;
} catch (error) {
const cachedResponse = await cache.match(request);
if (cachedResponse) {
return cachedResponse;
}
throw error;
}
},
// Stale-While-Revalidate
staleWhileRevalidate: async (request, options) => {
const { cache, network } = options;
const cachedResponse = await cache.match(request);
// 异步更新缓存
const updatePromise = network.fetch(request)
.then(networkResponse => {
cache.put(request, networkResponse.clone());
return networkResponse;
})
.catch(error => {
console.error('网络更新失败:', error);
});
// 返回缓存响应(如果存在)或等待网络响应
return cachedResponse || await updatePromise;
},
// 仅网络
networkOnly: async (request, options) => {
const { network } = options;
return await network.fetch(request);
},
// 仅缓存
cacheOnly: async (request, options) => {
const { cache } = options;
const cachedResponse = await cache.match(request);
if (!cachedResponse) {
throw new Error('缓存中未找到资源');
}
return cachedResponse;
}
};
// 使用示例
const strategyManager = new CacheStrategyManager();
// 注册策略
Object.entries(cacheStrategies).forEach(([name, strategy]) => {
strategyManager.registerStrategy(name, strategy);
});
// 执行策略
const response = await strategyManager.executeStrategy('cacheFirst', request, {
cache: caches.open('my-cache'),
network: { fetch }
});
性能优化
1. 缓存性能优化
性能优化策略:
2. 性能优化实现
缓存性能优化器:
// 缓存性能优化器
class CachePerformanceOptimizer {
constructor(cacheManager) {
this.cacheManager = cacheManager;
this.metrics = {
hitRate: 0,
missRate: 0,
averageResponseTime: 0,
memoryUsage: 0
};
this.init();
}
init() {
this.setupMetricsCollection();
this.setupPerformanceMonitoring();
this.setupOptimization();
}
setupMetricsCollection() {
// 收集缓存命中率
this.cacheManager.onHit = () => {
this.metrics.hitRate++;
this.updateHitRate();
};
this.cacheManager.onMiss = () => {
this.metrics.missRate++;
this.updateHitRate();
};
}
setupPerformanceMonitoring() {
// 监控响应时间
this.cacheManager.onRequest = (startTime) => {
const endTime = performance.now();
const responseTime = endTime - startTime;
this.updateAverageResponseTime(responseTime);
};
// 监控内存使用
setInterval(() => {
this.updateMemoryUsage();
}, 1000);
}
setupOptimization() {
// 自动清理过期缓存
setInterval(() => {
this.cacheManager.cleanup();
}, 300000); // 5分钟
// 根据命中率调整策略
setInterval(() => {
this.optimizeStrategy();
}, 60000); // 1分钟
}
updateHitRate() {
const total = this.metrics.hitRate + this.metrics.missRate;
this.metrics.hitRate = total > 0 ? this.metrics.hitRate / total : 0;
}
updateAverageResponseTime(responseTime) {
const total = this.metrics.hitRate + this.metrics.missRate;
this.metrics.averageResponseTime =
(this.metrics.averageResponseTime * (total - 1) + responseTime) / total;
}
updateMemoryUsage() {
if (performance.memory) {
this.metrics.memoryUsage = performance.memory.usedJSHeapSize;
}
}
optimizeStrategy() {
// 根据命中率调整缓存策略
if (this.metrics.hitRate < 0.5) {
// 命中率低,增加缓存时间
this.cacheManager.increaseTTL();
} else if (this.metrics.hitRate > 0.8) {
// 命中率高,减少缓存时间
this.cacheManager.decreaseTTL();
}
}
// 获取性能指标
getMetrics() {
return { ...this.metrics };
}
// 生成性能报告
generateReport() {
return {
hitRate: `${(this.metrics.hitRate * 100).toFixed(2)}%`,
missRate: `${(this.metrics.missRate * 100).toFixed(2)}%`,
averageResponseTime: `${this.metrics.averageResponseTime.toFixed(2)}ms`,
memoryUsage: `${(this.metrics.memoryUsage / 1024 / 1024).toFixed(2)}MB`
};
}
}
// 使用示例
const cacheManager = new ApplicationCacheManager();
const optimizer = new CachePerformanceOptimizer(cacheManager);
// 获取性能指标
const metrics = optimizer.getMetrics();
console.log('缓存性能指标:', metrics);
// 生成性能报告
const report = optimizer.generateReport();
console.log('缓存性能报告:', report);
最佳实践
1. 缓存最佳实践
最佳实践原则:
2. 开发最佳实践
开发规范:
-
策略选择
- 根据资源类型和更新频率选择合适的缓存策略
- 实现动态策略调整机制
- 提供降级处理方案
-
性能优化
- 实现内存管理和垃圾回收
- 优化网络请求和存储效率
- 使用压缩和CDN加速
-
错误处理
- 实现完善的错误处理机制
- 提供重试和降级方案
- 记录详细的错误日志
-
监控告警
- 监控缓存性能和命中率
- 设置告警机制
- 定期生成性能报告
通过以上资源缓存方案,可以构建出高效、可靠、性能优秀的前端缓存系统。