欢迎来到尧图网

客户服务 关于我们

您的位置:首页 > 科技 > 能源 > 工程化与框架系列(18)--前端缓存策略

工程化与框架系列(18)--前端缓存策略

2025/3/9 10:00:50 来源:https://blog.csdn.net/Chen7Chan/article/details/146040680  浏览:    关键词:工程化与框架系列(18)--前端缓存策略

前端缓存策略 🗄️

引言

缓存是提升Web应用性能的关键策略之一。合理的缓存策略可以显著减少网络请求,加快页面加载速度,提升用户体验。本文将深入探讨前端缓存的各种策略和最佳实践,帮助开发者构建高效的缓存系统。

缓存策略概述

前端缓存可以分为以下几个层面:

  • HTTP缓存:利用浏览器的HTTP缓存机制
  • 浏览器存储:LocalStorage、SessionStorage、IndexedDB等
  • 应用缓存:Service Worker、应用级缓存
  • CDN缓存:利用内容分发网络加速资源访问
  • 数据缓存:前端数据状态管理和缓存

HTTP缓存策略

强缓存与协商缓存

// 服务器端设置HTTP缓存头
app.get('/api/data', (req, res) => {// 强缓存:设置过期时间res.setHeader('Cache-Control', 'max-age=3600'); // 1小时res.setHeader('Expires', new Date(Date.now() + 3600000).toUTCString());// 协商缓存:设置ETag和Last-Modifiedconst etag = generateETag(data);const lastModified = new Date().toUTCString();res.setHeader('ETag', etag);res.setHeader('Last-Modified', lastModified);// 检查协商缓存const ifNoneMatch = req.headers['if-none-match'];const ifModifiedSince = req.headers['if-modified-since'];if (ifNoneMatch === etag || new Date(ifModifiedSince) >= new Date(lastModified)) {res.status(304).end(); // Not Modifiedreturn;}res.json(data);
});// 前端请求处理
async function fetchDataWithCache() {try {const response = await fetch('/api/data', {headers: {'Cache-Control': 'max-age=3600','If-None-Match': localStorage.getItem('etag'),'If-Modified-Since': localStorage.getItem('lastModified')}});if (response.status === 304) {return JSON.parse(localStorage.getItem('cachedData') || '{}');}const data = await response.json();// 保存缓存相关信息localStorage.setItem('etag', response.headers.get('ETag') || '');localStorage.setItem('lastModified', response.headers.get('Last-Modified') || '');localStorage.setItem('cachedData', JSON.stringify(data));return data;} catch (error) {console.error('数据获取失败:', error);return JSON.parse(localStorage.getItem('cachedData') || '{}');}
}

缓存控制策略

// 缓存控制工具类
class CacheController {private static instance: CacheController;private cacheConfig: Map<string, CacheStrategy>;private constructor() {this.cacheConfig = new Map();}static getInstance(): CacheController {if (!CacheController.instance) {CacheController.instance = new CacheController();}return CacheController.instance;}// 设置资源缓存策略setCacheStrategy(resource: string, strategy: CacheStrategy): void {this.cacheConfig.set(resource, strategy);}// 获取资源缓存策略getCacheStrategy(resource: string): CacheStrategy | undefined {return this.cacheConfig.get(resource);}
}interface CacheStrategy {maxAge: number;revalidate: boolean;staleWhileRevalidate?: number;
}// 使用示例
const cacheController = CacheController.getInstance();// 设置不同资源的缓存策略
cacheController.setCacheStrategy('/api/user', {maxAge: 3600,revalidate: true,staleWhileRevalidate: 300
});cacheController.setCacheStrategy('/api/static-data', {maxAge: 86400, // 24小时revalidate: false
});

浏览器存储策略

LocalStorage与SessionStorage

// 浏览器存储管理类
class StorageManager {private storage: Storage;private prefix: string;constructor(useSession: boolean = false, prefix: string = 'app_') {this.storage = useSession ? sessionStorage : localStorage;this.prefix = prefix;}// 存储数据setItem(key: string, value: any, expires?: number): void {const item = {value,timestamp: Date.now(),expires: expires ? Date.now() + expires * 1000 : null};this.storage.setItem(this.prefix + key, JSON.stringify(item));}// 获取数据getItem<T>(key: string): T | null {const item = this.storage.getItem(this.prefix + key);if (!item) return null;const { value, timestamp, expires } = JSON.parse(item);// 检查是否过期if (expires && Date.now() > expires) {this.removeItem(key);return null;}return value as T;}// 删除数据removeItem(key: string): void {this.storage.removeItem(this.prefix + key);}// 清理过期数据clearExpired(): void {const keys = Object.keys(this.storage);keys.forEach(key => {if (key.startsWith(this.prefix)) {const item = this.storage.getItem(key);if (item) {const { expires } = JSON.parse(item);if (expires && Date.now() > expires) {this.storage.removeItem(key);}}}});}
}// 使用示例
const storage = new StorageManager();// 存储用户数据,1小时后过期
storage.setItem('user', { id: 1, name: 'John' }, 3600);// 获取用户数据
const user = storage.getItem<{ id: number, name: string }>('user');// 定期清理过期数据
setInterval(() => storage.clearExpired(), 300000); // 每5分钟清理一次

IndexedDB缓存

// IndexedDB管理类
class IndexedDBManager {private dbName: string;private version: number;constructor(dbName: string, version: number = 1) {this.dbName = dbName;this.version = version;}// 打开数据库async openDB(): Promise<IDBDatabase> {return new Promise((resolve, reject) => {const request = indexedDB.open(this.dbName, this.version);request.onerror = () => reject(request.error);request.onsuccess = () => resolve(request.result);request.onupgradeneeded = (event) => {const db = (event.target as IDBOpenDBRequest).result;// 创建存储对象if (!db.objectStoreNames.contains('cache')) {db.createObjectStore('cache', { keyPath: 'id' });}};});}// 存储数据async setCache(key: string, data: any): Promise<void> {const db = await this.openDB();return new Promise((resolve, reject) => {const transaction = db.transaction(['cache'], 'readwrite');const store = transaction.objectStore('cache');const request = store.put({id: key,data,timestamp: Date.now()});request.onsuccess = () => resolve();request.onerror = () => reject(request.error);});}// 获取数据async getCache(key: string): Promise<any> {const db = await this.openDB();return new Promise((resolve, reject) => {const transaction = db.transaction(['cache'], 'readonly');const store = transaction.objectStore('cache');const request = store.get(key);request.onsuccess = () => resolve(request.result?.data);request.onerror = () => reject(request.error);});}
}// 使用示例
const dbManager = new IndexedDBManager('myApp');// 存储大量数据
await dbManager.setCache('userList', largeUserArray);// 获取数据
const users = await dbManager.getCache('userList');

Service Worker缓存

基础缓存策略

// Service Worker安装
self.addEventListener('install', (event: ExtendableEvent) => {event.waitUntil(caches.open('v1').then(cache => {return cache.addAll(['/','/styles/main.css','/scripts/app.js','/images/logo.png']);}));
});// 缓存优先策略
self.addEventListener('fetch', (event: FetchEvent) => {event.respondWith(caches.match(event.request).then(response => {return response || fetch(event.request).then(response => {// 克隆响应,因为响应流只能被读取一次const responseClone = response.clone();caches.open('v1').then(cache => {cache.put(event.request, responseClone);});return response;});}));
});

高级缓存策略

// 缓存策略管理器
class CacheStrategyManager {// 网络优先策略static async networkFirst(request: Request): Promise<Response> {try {// 尝试网络请求const networkResponse = await fetch(request);// 更新缓存const cache = await caches.open('v1');cache.put(request, networkResponse.clone());return networkResponse;} catch (error) {// 网络请求失败,尝试使用缓存const cachedResponse = await caches.match(request);if (cachedResponse) {return cachedResponse;}throw new Error('No cached response available');}}// 缓存优先策略static async cacheFirst(request: Request): Promise<Response> {const cachedResponse = await caches.match(request);if (cachedResponse) {// 后台更新缓存this.updateCache(request);return cachedResponse;}return this.networkFirst(request);}// 后台更新缓存private static async updateCache(request: Request): Promise<void> {try {const networkResponse = await fetch(request);const cache = await caches.open('v1');await cache.put(request, networkResponse);} catch (error) {console.warn('Background cache update failed:', error);}}
}// 使用不同的缓存策略
self.addEventListener('fetch', (event: FetchEvent) => {const url = new URL(event.request.url);// API请求使用网络优先策略if (url.pathname.startsWith('/api/')) {event.respondWith(CacheStrategyManager.networkFirst(event.request));}// 静态资源使用缓存优先策略else if (url.pathname.match(/\.(css|js|png|jpg|jpeg|gif|svg)$/)) {event.respondWith(CacheStrategyManager.cacheFirst(event.request));}
});

CDN缓存策略

CDN配置与使用

// CDN配置管理器
class CDNManager {private cdnUrl: string;private fallbackUrl: string;constructor(cdnUrl: string, fallbackUrl: string) {this.cdnUrl = cdnUrl;this.fallbackUrl = fallbackUrl;}// 生成CDN URLgenerateUrl(path: string): string {return `${this.cdnUrl}${path}`;}// 加载资源async loadResource(path: string): Promise<string> {try {const response = await fetch(this.generateUrl(path));if (!response.ok) {throw new Error('CDN resource not available');}return await response.text();} catch (error) {console.warn('CDN加载失败,使用备用地址:', error);return this.loadFromFallback(path);}}// 从备用地址加载private async loadFromFallback(path: string): Promise<string> {const response = await fetch(`${this.fallbackUrl}${path}`);return response.text();}
}// 使用示例
const cdnManager = new CDNManager('https://cdn.example.com','https://backup.example.com'
);// 加载资源
const styles = await cdnManager.loadResource('/styles/main.min.css');

数据缓存策略

前端状态缓存

// 状态缓存管理器
class StateCache {private cache: Map<string, any>;private expirations: Map<string, number>;constructor() {this.cache = new Map();this.expirations = new Map();}// 设置缓存setState(key: string, value: any, ttl?: number): void {this.cache.set(key, value);if (ttl) {this.expirations.set(key, Date.now() + ttl * 1000);}}// 获取缓存getState(key: string): any {// 检查是否过期const expiration = this.expirations.get(key);if (expiration && Date.now() > expiration) {this.cache.delete(key);this.expirations.delete(key);return null;}return this.cache.get(key);}// 清除缓存clearState(key?: string): void {if (key) {this.cache.delete(key);this.expirations.delete(key);} else {this.cache.clear();this.expirations.clear();}}
}// 使用示例
const stateCache = new StateCache();// 缓存用户数据,有效期1小时
stateCache.setState('currentUser', { id: 1, name: 'John' }, 3600);// 获取缓存数据
const user = stateCache.getState('currentUser');

API响应缓存

// API缓存管理器
class APICache {private cache: Map<string, {data: any;timestamp: number;ttl: number;}>;constructor() {this.cache = new Map();}// 生成缓存键private generateCacheKey(url: string, params?: object): string {return `${url}:${JSON.stringify(params || {})}`;}// 检查缓存是否有效private isValid(cacheKey: string): boolean {const cached = this.cache.get(cacheKey);if (!cached) return false;return Date.now() - cached.timestamp < cached.ttl * 1000;}// 缓存API响应async cacheApiResponse(url: string,params?: object,ttl: number = 300 // 默认5分钟): Promise<any> {const cacheKey = this.generateCacheKey(url, params);// 检查缓存if (this.isValid(cacheKey)) {return this.cache.get(cacheKey)!.data;}// 发起API请求const response = await fetch(url, {method: 'POST',headers: {'Content-Type': 'application/json'},body: JSON.stringify(params)});const data = await response.json();// 更新缓存this.cache.set(cacheKey, {data,timestamp: Date.now(),ttl});return data;}// 清除指定URL的缓存clearCache(url: string, params?: object): void {const cacheKey = this.generateCacheKey(url, params);this.cache.delete(cacheKey);}// 清除所有缓存clearAllCache(): void {this.cache.clear();}
}// 使用示例
const apiCache = new APICache();// 使用缓存获取数据
const getData = async () => {try {const data = await apiCache.cacheApiResponse('/api/data',{ type: 'users' },600 // 10分钟缓存);return data;} catch (error) {console.error('数据获取失败:', error);throw error;}
};

最佳实践与建议

  1. 分层缓存策略

    • 合理使用不同级别的缓存
    • 根据数据特性选择合适的缓存方式
    • 实现缓存预热和更新机制
  2. 缓存失效处理

    • 实现优雅的降级策略
    • 处理缓存过期和清理
    • 监控缓存命中率
  3. 性能优化

    • 避免缓存过大数据量
    • 定期清理无用缓存
    • 实现缓存预加载
  4. 安全考虑

    • 不缓存敏感数据
    • 实现缓存数据加密
    • 防止缓存投毒攻击

总结

前端缓存策略是提升应用性能的关键手段。通过合理运用各种缓存机制,可以:

  1. 减少网络请求
  2. 提升响应速度
  3. 改善用户体验
  4. 降低服务器负载
  5. 优化资源利用

选择合适的缓存策略需要考虑数据特性、更新频率、安全要求等多个因素,并在实践中不断优化和调整。

学习资源

  1. MDN Web缓存指南
  2. Chrome开发者工具文档
  3. Service Worker教程
  4. HTTP缓存规范
  5. 前端性能优化实践

如果你觉得这篇文章有帮助,欢迎点赞收藏,也期待在评论区看到你的想法和建议!👇

终身学习,共同成长。

咱们下一期见

💻

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com

热搜词