/** * 浏览器缓存管理模块 * 使用LocalStorage实现24小时过期缓存 */ class BrowserCache { constructor() { this.CACHE_EXPIRE_HOURS = 24; this.CACHE_KEY_PREFIX = 'pfp_'; } /** * 设置缓存 * @param {string} key - 缓存键名 * @param {*} data - 要缓存的数据 */ setCache(key, data) { const now = Date.now(); const cacheData = { timestamp: now, expireAt: now + (this.CACHE_EXPIRE_HOURS * 60 * 60 * 1000), data: data }; try { localStorage.setItem( this.CACHE_KEY_PREFIX + key, JSON.stringify(cacheData) ); console.log(`缓存已保存: ${key}, 过期时间: ${new Date(cacheData.expireAt).toLocaleString()}`); } catch (e) { console.error('缓存保存失败:', e); // LocalStorage空间不足时,清理旧缓存 if (e.name === 'QuotaExceededError') { console.warn('LocalStorage空间不足,清理过期缓存...'); this.clearExpiredCache(); // 再次尝试保存 try { localStorage.setItem( this.CACHE_KEY_PREFIX + key, JSON.stringify(cacheData) ); console.log(`清理后重新保存成功: ${key}`); } catch (e2) { console.error('清理后仍然无法保存:', e2); } } } } /** * 获取缓存 * @param {string} key - 缓存键名 * @returns {*} 缓存的数据,如果不存在或过期则返回null */ getCache(key) { try { const cacheStr = localStorage.getItem(this.CACHE_KEY_PREFIX + key); if (!cacheStr) { return null; } const cacheData = JSON.parse(cacheStr); const now = Date.now(); // 检查是否过期 if (now > cacheData.expireAt) { console.log(`缓存已过期: ${key}`); this.removeCache(key); return null; } const remainingHours = ((cacheData.expireAt - now) / (60 * 60 * 1000)).toFixed(1); console.log(`使用缓存: ${key}, 剩余有效时间: ${remainingHours}小时`); return cacheData.data; } catch (e) { console.error('缓存读取失败:', e); return null; } } /** * 删除缓存 * @param {string} key - 缓存键名 */ removeCache(key) { localStorage.removeItem(this.CACHE_KEY_PREFIX + key); console.log(`缓存已删除: ${key}`); } /** * 清理所有过期缓存 */ clearExpiredCache() { const now = Date.now(); let clearedCount = 0; Object.keys(localStorage).forEach(key => { if (key.startsWith(this.CACHE_KEY_PREFIX)) { try { const cacheData = JSON.parse(localStorage.getItem(key)); if (now > cacheData.expireAt) { localStorage.removeItem(key); clearedCount++; console.log(`已清理过期缓存: ${key}`); } } catch (e) { // 损坏的缓存数据,直接删除 localStorage.removeItem(key); clearedCount++; console.warn(`已清理损坏缓存: ${key}`); } } }); if (clearedCount > 0) { console.log(`清理完成,共清理 ${clearedCount} 个缓存项`); } } /** * 清空所有PFP相关缓存 */ clearAllCache() { let clearedCount = 0; Object.keys(localStorage).forEach(key => { if (key.startsWith(this.CACHE_KEY_PREFIX)) { localStorage.removeItem(key); clearedCount++; } }); console.log(`已清空所有缓存,共 ${clearedCount} 项`); } /** * 获取缓存统计信息 * @returns {Object} 缓存统计 */ getCacheStats() { const stats = { total: 0, expired: 0, valid: 0, totalSize: 0, items: [] }; const now = Date.now(); Object.keys(localStorage).forEach(key => { if (key.startsWith(this.CACHE_KEY_PREFIX)) { try { const value = localStorage.getItem(key); const cacheData = JSON.parse(value); const isExpired = now > cacheData.expireAt; const size = new Blob([value]).size; stats.total++; stats.totalSize += size; if (isExpired) { stats.expired++; } else { stats.valid++; } stats.items.push({ key: key.replace(this.CACHE_KEY_PREFIX, ''), size: (size / 1024).toFixed(2) + 'KB', expireAt: new Date(cacheData.expireAt), isExpired: isExpired }); } catch (e) { console.warn(`无法解析缓存: ${key}`, e); } } }); stats.totalSize = (stats.totalSize / 1024).toFixed(2) + 'KB'; return stats; } } // 页面加载时自动清理过期缓存 window.addEventListener('DOMContentLoaded', () => { const cache = new BrowserCache(); cache.clearExpiredCache(); }); // 监听storage事件,处理多标签页同步 window.addEventListener('storage', (e) => { if (e.key && e.key.startsWith('pfp_')) { console.log('缓存已在其他标签页更新:', e.key); } }); // 调试工具:挂载到全局对象 window.PFPCacheDebug = { showStats() { const cache = new BrowserCache(); const stats = cache.getCacheStats(); console.table(stats.items); console.log(`总计: ${stats.total} 项, 有效: ${stats.valid} 项, 过期: ${stats.expired} 项, 总大小: ${stats.totalSize}`); }, clearAll() { const cache = new BrowserCache(); cache.clearAllCache(); console.log('缓存已清空,刷新页面生效'); }, forceRefresh() { const cache = new BrowserCache(); cache.clearAllCache(); location.reload(); } };