前端缓存全解析:提升性能的关键策略

前端缓存技术深度解析:从原理到实践

目录

  1. 缓存概述
  2. HTTP 缓存(浏览器缓存)
  3. Service Worker 缓存
  4. 内存缓存
  5. 状态管理缓存
  6. 浏览器存储缓存
  7. 缓存策略详解
  8. 实际应用场景
  9. 性能优化实践
  10. 缓存失效与更新
  11. 常见问题与解决方案
  12. 最佳实践
  13. 总结

缓存概述

什么是缓存

缓存(Cache)是一种存储数据的技术,其核心目标是通过存储数据的副本,在后续请求中直接返回这些副本,从而提高数据访问速度和系统性能。

为什么需要缓存

在 Web 应用中,缓存的重要性不言而喻:

无缓存场景: 用户请求 → 服务器处理 → 数据库查询 → 数据处理 → 响应返回 ↑ ↓ 慢(多次网络往返 + 复杂计算) 耗时:500-2000ms 有缓存场景: 用户请求 → 缓存检查 → 直接返回 ↑ ↓ 快(内存访问) 耗时:1-50ms 

缓存的优势

  1. 提升性能:减少网络请求,加快页面加载速度
  2. 降低服务器负载:减少数据库查询和计算
  3. 节省带宽:减少数据传输量
  4. 改善用户体验:离线可用,快速响应
  5. 降低成本:减少服务器资源消耗

缓存的挑战

  1. 数据一致性:缓存数据可能与源数据不同步
  2. 缓存穿透:请求不存在的数据导致缓存失效
  3. 缓存雪崩:大量缓存同时失效导致请求涌入后端
  4. 缓存击穿:热点数据失效时大量请求直达数据库
  5. 存储空间限制:浏览器存储空间有限

缓存层级模型

┌─────────────────────────────────────┐ │ 用户请求 │ └─────────────────┬───────────────────┘ │ ┌─────────────────▼───────────────────┐ │ 浏览器缓存 │ │ ┌──────────┐ ┌──────────┐ │ │ │ HTTP │ │ Service │ │ │ │ 缓存 │ │ Worker │ │ │ └──────────┘ └──────────┘ │ └─────────────────┬───────────────────┘ │ ┌─────────────────▼───────────────────┐ │ 应用内存缓存 │ │ ┌──────────────────────┐ │ │ │ React/Vue │ │ │ │ 状态缓存 │ │ │ └──────────────────────┘ │ └─────────────────┬───────────────────┘ │ ┌─────────────────▼───────────────────┐ │ 服务器缓存 │ │ ┌──────────────────────┐ │ │ │ Redis / Memcached │ │ │ └──────────────────────┘ │ └─────────────────┬───────────────────┘ │ ┌─────────────────▼───────────────────┐ │ 数据库缓存 │ │ ┌──────────────────────┐ │ │ │ 查询结果缓存 │ │ │ └──────────────────────┘ │ └─────────────────────────────────────┘ 

HTTP 缓存(浏览器缓存)

HTTP 缓存是浏览器最基础的缓存机制,通过 HTTP 头信息控制资源的缓存行为。

1. 强缓存

强缓存(Strong Cache)不会向服务器发送请求,直接从缓存中获取资源。

Cache-Control
Cache-Control: max-age=3600 

常用指令:

  • max-age=<seconds>:缓存有效期(秒)
  • no-cache:需要验证缓存有效性
  • no-store:完全不使用缓存
  • public:响应可被任何缓存存储
  • private:响应只能被私有缓存存储
  • immutable:资源不会更新
// Node.js 服务器端设置 app.get('/api/data',(req, res)=>{ res.set('Cache-Control','public, max-age=3600');// 缓存1小时 res.json({data:'some data'});});// 静态资源长期缓存 app.use('/static', express.static('public',{setHeaders:(res, path)=>{ res.set('Cache-Control','public, max-age=31536000, immutable');}}));
# Nginx 配置 location ~* \.(js|css|png|jpg|jpeg|gif|ico|svg)$ { expires 1y; add_header Cache-Control "public, immutable"; } location /api/ { expires 5m; add_header Cache-Control "public"; } 
Expires
Expires: Wed, 21 Oct 2026 07:28:00 GMT 
// 设置过期时间 res.set('Expires',newDate(Date.now()+3600000).toUTCString());

注意:Expires 是 HTTP/1.0 的产物,Cache-Control 是 HTTP/1.1 的改进,优先级更高。

2. 协商缓存

协商缓存(Conditional Cache)需要向服务器验证资源是否更新。

Last-Modified / If-Modified-Since
Last-Modified: Wed, 21 Oct 2026 07:28:00 GMT 
// 服务器端实现 app.get('/api/data',(req, res)=>{const lastModified =newDate('2026-01-05').toUTCString();const ifModifiedSince = req.get('If-Modified-Since');if(ifModifiedSince === lastModified){return res.status(304).end();// 未修改} res.set('Last-Modified', lastModified); res.json({data:'some data'});});
ETag / If-None-Match
ETag: "abc123" 
// 服务器端实现const crypto =require('crypto'); app.get('/api/data',(req, res)=>{const data =JSON.stringify({data:'some data'});const etag = crypto.createHash('md5').update(data).digest('hex');const ifNoneMatch = req.get('If-None-Match');if(ifNoneMatch === etag){return res.status(304).end();} res.set('ETag', etag); res.json(JSON.parse(data));});

ETag vs Last-Modified

特性ETagLast-Modified
精度基于内容哈希基于时间戳
准确性更高可能不准确(秒级)
优先级更高较低
支持度现代浏览器广泛支持所有浏览器支持

3. 缓存控制指令

常用指令组合
// 不缓存 res.set('Cache-Control','no-store, no-cache, must-revalidate');// 短时间缓存 res.set('Cache-Control','public, max-age=300');// 5分钟// 长时间缓存(静态资源) res.set('Cache-Control','public, max-age=31536000, immutable');// 私有缓存(敏感数据) res.set('Cache-Control','private, max-age=3600');// 代理缓存 res.set('Cache-Control','public, s-maxage=3600');
Vary 头
Vary: Accept-Encoding 
// 根据 Accept-Encoding 缓存不同版本 res.set('Vary','Accept-Encoding, User-Agent');

Service Worker 缓存

Service Worker 是在浏览器后台运行的脚本,提供了强大的缓存控制能力。

1. Cache Storage

// 注册 Service Workerif('serviceWorker'in navigator){ navigator.serviceWorker.register('/sw.js').then(registration=>{ console.log('SW registered:', registration);});}
// sw.js - Service Worker 文件constCACHE_NAME='my-app-v1';const urlsToCache =['/','/static/js/main.js','/static/css/main.css','/api/user-data'];// 安装阶段 - 缓存资源 self.addEventListener('install',event=>{ event.waitUntil( caches.open(CACHE_NAME).then(cache=>{ console.log('Opened cache');return cache.addAll(urlsToCache);}));});// 激活阶段 - 清理旧缓存 self.addEventListener('activate',event=>{ event.waitUntil( caches.keys().then(cacheNames=>{return Promise.all( cacheNames.map(cacheName=>{if(cacheName !==CACHE_NAME){return caches.delete(cacheName);}}));}));});// 拦截请求 self.addEventListener('fetch',event=>{ event.respondWith( caches.match(event.request).then(response=>{// 如果缓存中有,直接返回if(response){return response;}// 否则请求网络returnfetch(event.request);}));});

2. 缓存策略

Cache First(缓存优先)
self.addEventListener('fetch',event=>{// 只缓存 GET 请求if(event.request.method !=='GET')return; event.respondWith( caches.match(event.request).then(cachedResponse=>{if(cachedResponse){return cachedResponse;}returnfetch(event.request).then(response=>{// 检查响应是否有效if(!response || response.status !==200|| response.type !=='basic'){return response;}// 克隆响应并缓存const responseToCache = response.clone(); caches.open(CACHE_NAME).then(cache=>{ cache.put(event.request, responseToCache);});return response;});}));});
Network First(网络优先)
self.addEventListener('fetch',event=>{if(event.request.method !=='GET')return; event.respondWith(fetch(event.request).then(response=>{// 网络请求成功,缓存响应const responseClone = response.clone(); caches.open(CACHE_NAME).then(cache=>{ cache.put(event.request, responseClone);});return response;}).catch(()=>{// 网络请求失败,使用缓存return caches.match(event.request);}));});
Stale While Revalidate(过期数据可用,同时后台更新)
self.addEventListener('fetch',event=>{if(event.request.method !=='GET')return; event.respondWith( caches.match(event.request).then(cachedResponse=>{const networkFetch =fetch(event.request).then(response=>{// 更新缓存const responseClone = response.clone(); caches.open(CACHE_NAME).then(cache=>{ cache.put(event.request, responseClone);});return response;}).catch(()=>{// 网络请求失败 console.error('Network fetch failed');});// 立即返回缓存,同时后台更新return cachedResponse || networkFetch;}));});

3. 离线优先

// IndexedDB 辅助类classIDBHelper{constructor(dbName, storeName){this.dbName = dbName;this.storeName = storeName;this.db =null;}asyncinit(){returnnewPromise((resolve, reject)=>{const request = indexedDB.open(this.dbName,1); request.onerror=()=>reject(request.error); request.onsuccess=()=>{this.db = request.result;resolve(this.db);}; request.onupgradeneeded=(event)=>{const db = event.target.result;if(!db.objectStoreNames.contains(this.storeName)){ db.createObjectStore(this.storeName,{keyPath:'id'});}};});}asyncget(key){returnnewPromise((resolve, reject)=>{const transaction =this.db.transaction([this.storeName],'readonly');const store = transaction.objectStore(this.storeName);const request = store.get(key); request.onerror=()=>reject(request.error); request.onsuccess=()=>resolve(request.result);});}asyncset(value){returnnewPromise((resolve, reject)=>{const transaction =this.db.transaction([this.storeName],'readwrite');const store = transaction.objectStore(this.storeName);const request = store.put(value); request.onerror=()=>reject(request.error); request.onsuccess=()=>resolve(request.result);});}}// 使用 IndexedDB 缓存数据const idbHelper =newIDBHelper('MyAppDB','apiCache'); self.addEventListener('fetch',event=>{if(event.request.url.includes('/api/')){ event.respondWith((async()=>{try{// 尝试网络请求const networkResponse =awaitfetch(event.request);// 缓存响应if(networkResponse.ok){await idbHelper.set({id: event.request.url,data:await networkResponse.clone().json(),timestamp: Date.now()});}return networkResponse;}catch(error){// 网络失败,尝试缓存const cached =await idbHelper.get(event.request.url);if(cached){returnnewResponse(JSON.stringify(cached.data),{headers:{'Content-Type':'application/json'}});}// 没有缓存,返回离线页面returnnewResponse('Offline',{status:503});}})());}});

内存缓存

内存缓存是在应用运行期间将数据存储在内存中的缓存方式。

1. 内存数据结构

Map 缓存
classSimpleCache{constructor(){this.cache =newMap();}set(key, value, ttl =0){const expires = ttl >0? Date.now()+ ttl :0;this.cache.set(key,{ value, expires });}get(key){const item =this.cache.get(key);if(!item)returnnull;// 检查是否过期if(item.expires && item.expires < Date.now()){this.cache.delete(key);returnnull;}return item.value;}delete(key){this.cache.delete(key);}clear(){this.cache.clear();}// 获取缓存大小size(){returnthis.cache.size;}// 清理过期项cleanup(){const now = Date.now();for(const[key, item]ofthis.cache.entries()){if(item.expires && item.expires < now){this.cache.delete(key);}}}}// 使用示例const cache =newSimpleCache();// 缓存用户信息,10分钟过期 cache.set('user:123',{name:'张三',age:25},10*60*1000);const user = cache.get('user:123'); console.log(user);// { name: '张三', age: 25 }
WeakMap 缓存
classWeakRefCache{constructor(){this.cache =newWeakMap();this.timeouts =newWeakMap();}set(key, value, ttl =0){this.cache.set(key,{ value,timestamp: Date.now()});if(ttl >0){const timeoutId =setTimeout(()=>{this.delete(key);}, ttl);this.timeouts.set(key, timeoutId);}}get(key){const item =this.cache.get(key);return item ? item.value :null;}delete(key){this.cache.delete(key);const timeoutId =this.timeouts.get(key);if(timeoutId){clearTimeout(timeoutId);this.timeouts.delete(key);}}}// 使用示例const weakCache =newWeakRefCache();// 缓存 DOM 元素相关数据const element = document.querySelector('#myElement'); weakCache.set(element,{data:'some data'},5*60*1000);

2. LRU 缓存实现

classLRUCache{constructor(limit =100){this.limit = limit;this.cache =newMap();}get(key){if(!this.cache.has(key))returnnull;const value =this.cache.get(key).value;// 将访问的项移到末尾(最近使用)this.cache.delete(key);this.cache.set(key,{ value,timestamp: Date.now()});return value;}set(key, value, ttl =0){// 检查是否已存在if(this.cache.has(key)){this.cache.delete(key);}elseif(this.cache.size >=this.limit){// 删除最久未使用的项(第一个)const firstKey =this.cache.keys().next().value;this.cache.delete(firstKey);}const expires = ttl >0? Date.now()+ ttl :0;this.cache.set(key,{ value, expires,timestamp: Date.now()});}has(key){const item =this.cache.get(key);if(!item)returnfalse;if(item.expires && item.expires < Date.now()){this.cache.delete(key);returnfalse;}returntrue;}delete(key){this.cache.delete(key);}clear(){this.cache.clear();}// 获取所有有效项getValidItems(){const now = Date.now();const validItems =[];for(const[key, item]ofthis.cache.entries()){if(!item.expires || item.expires >= now){ validItems.push({ key,value: item.value });}else{this.cache.delete(key);}}return validItems;}}// 使用示例const lruCache =newLRUCache(50);// 缓存 API 响应asyncfunctionfetchWithCache(url, ttl =5*60*1000){if(lruCache.has(url)){ console.log('使用缓存:', url);return lruCache.get(url);}const response =awaitfetch(url);const data =await response.json(); lruCache.set(url, data, ttl);return data;}

3. 内存缓存管理

缓存管理器
classCacheManager{constructor(){this.caches =newMap();this.cleanupInterval =null;}createCache(name, options ={}){const{ limit =100, ttl =0}= options;if(this.caches.has(name)){returnthis.caches.get(name);}const cache =newLRUCache(limit);const cacheWrapper ={ name,set:(key, value)=> cache.set(key, value, ttl),get:(key)=> cache.get(key),has:(key)=> cache.has(key),delete:(key)=> cache.delete(key),clear:()=> cache.clear(),size:()=> cache.cache.size,getStats:()=>({ name,size: cache.cache.size, limit, ttl })};this.caches.set(name, cacheWrapper);return cacheWrapper;}getCache(name){returnthis.caches.get(name);}deleteCache(name){const cache =this.caches.get(name);if(cache){ cache.clear();this.caches.delete(name);}}clearAll(){for(const cache ofthis.caches.values()){ cache.clear();}}getAllStats(){const stats =[];for(const cache ofthis.caches.values()){ stats.push(cache.getStats());}return stats;}// 启动定期清理startCleanup(interval =60000){if(this.cleanupInterval)return;this.cleanupInterval =setInterval(()=>{for(const cache ofthis.caches.values()){const validItems = cache.getValidItems?.();if(validItems){ console.log(`清理缓存 ${cache.name},剩余有效项: ${validItems.length}`);}}}, interval);}stopCleanup(){if(this.cleanupInterval){clearInterval(this.cleanupInterval);this.cleanupInterval =null;}}}// 全局缓存管理器实例const cacheManager =newCacheManager();// 创建不同类型的缓存const apiCache = cacheManager.createCache('api',{limit:200,ttl:300000});const componentCache = cacheManager.createCache('component',{limit:50,ttl:600000});const userCache = cacheManager.createCache('user',{limit:100,ttl:600000});// 启动定期清理 cacheManager.startCleanup();// 在页面卸载时清理 window.addEventListener('beforeunload',()=>{ cacheManager.stopCleanup();});

状态管理缓存

1. Redux 缓存

// 使用 redux-persist 持久化状态import{ persistStore, persistReducer }from'redux-persist';import storage from'redux-persist/lib/storage';import{ configureStore }from'@reduxjs/toolkit';import userReducer from'./userSlice';// 配置持久化const persistConfig ={key:'root', storage,whitelist:['user','settings'],// 只持久化这些 reducerblacklist:['temp']// 不持久化这些 reducer};const persistedReducer =persistReducer(persistConfig, rootReducer);const store =configureStore({reducer: persistedReducer,middleware:(getDefaultMiddleware)=>getDefaultMiddleware({serializableCheck:{ignoredActions:[FLUSH,REHYDRATE,PAUSE,PERSIST,PURGE,REGISTER]}})});const persistor =persistStore(store);// 在组件中使用import{ useSelector }from'react-redux';functionUserProfile(){const user =useSelector((state)=> state.user.data);const isLoading =useSelector((state)=> state.user.loading);if(isLoading)return<div>加载中...</div>;return<div>{user.name}</div>;}
自定义中间件缓存
// API 缓存中间件constapiCacheMiddleware=(store)=>(next)=>(action)=>{const{ type, payload }= action;// 如果是 API 请求if(type.startsWith('api/')){const cacheKey =JSON.stringify(payload);const cachedData =getFromCache(cacheKey);if(cachedData &&!payload.forceRefresh){// 返回缓存数据return{type:`${type}_SUCCESS`,payload: cachedData };}}const result =next(action);// 如果请求成功,缓存结果if(type.endsWith('_SUCCESS')){const{ url, ttl =300000}= payload;setCache(url, action.payload, ttl);}return result;};// 使用缓存中间件const store =configureStore({reducer: rootReducer,middleware:(getDefaultMiddleware)=>getDefaultMiddleware().concat(apiCacheMiddleware)});

2. Vuex/Pinia 缓存

// Pinia 缓存插件exportfunctioncachePlugin({ store }){// 从 localStorage 恢复状态const savedState = localStorage.getItem('pinia-state');if(savedState){ store.$patch(JSON.parse(savedState));}// 状态变化时保存到 localStorage store.$subscribe((mutation, state)=>{ localStorage.setItem('pinia-state',JSON.stringify(state));});}// main.jsimport{ createPinia }from'pinia';import{ cachePlugin }from'./plugins/cache';const pinia =createPinia(); pinia.use(cachePlugin); app.use(pinia);
Pinia 缓存 Store
// stores/cache.jsimport{ defineStore }from'pinia';import axios from'axios';exportconst useCacheStore =defineStore('cache',{state:()=>({_cache:newMap(),_timestamps:newMap()}),actions:{asyncget(key, fetcher, ttl =300000){// 检查缓存是否存在且未过期if(this._cache.has(key)){const timestamp =this._timestamps.get(key);if(Date.now()- timestamp < ttl){returnthis._cache.get(key);}}// 获取新数据const data =awaitfetcher();this._cache.set(key, data);this._timestamps.set(key, Date.now());return data;},set(key, value){this._cache.set(key, value);this._timestamps.set(key, Date.now());},delete(key){this._cache.delete(key);this._timestamps.delete(key);},clear(){this._cache.clear();this._timestamps.clear();}}});// 使用缓存 Storeconst cacheStore =useCacheStore();const userData =await cacheStore.get('user:123',async()=>{const response =await axios.get('/api/user/123');return response.data;});

3. React Query 缓存

// React Query 配置import{ QueryClient, QueryClientProvider }from'@tanstack/react-query';const queryClient =newQueryClient({defaultOptions:{queries:{staleTime:5*60*1000,// 5分钟内数据新鲜cacheTime:10*60*1000,// 10分钟后清理缓存retry:3,refetchOnWindowFocus:false}}});functionApp(){return(<QueryClientProvider client={queryClient}><UserProfile /></QueryClientProvider>);}// 使用 React Queryimport{ useQuery }from'@tanstack/react-query';functionUserProfile({ userId }){const{ data, isLoading, error }=useQuery(['user', userId],async()=>{const response =awaitfetch(`/api/user/${userId}`);if(!response.ok)thrownewError('Network error');return response.json();},{staleTime:5*60*1000,// 缓存5分钟cacheTime:10*60*1000,enabled:!!userId // 只有 userId 存在时才执行查询});if(isLoading)return<div>加载中...</div>;if(error)return<div>错误:{error.message}</div>;return<div>{data.name}</div>;}// 手动操作缓存functionupdateUser(){ queryClient.setQueryData(['user', userId],(oldData)=>({...oldData,name:'新名称'}));// 失效缓存 queryClient.invalidateQueries(['user']);}

浏览器存储缓存

1. LocalStorage

// LocalStorage 封装类classLocalStorageCache{constructor(prefix ='cache_'){this.prefix = prefix;}set(key, value, ttl =0){const data ={ value,timestamp: Date.now(),ttl: ttl >0? ttl :null}; localStorage.setItem(this.prefix + key,JSON.stringify(data));}get(key){const item = localStorage.getItem(this.prefix + key);if(!item)returnnull;try{const data =JSON.parse(item);// 检查是否过期if(data.ttl && Date.now()- data.timestamp > data.ttl){this.delete(key);returnnull;}return data.value;}catch(error){ console.error('Parse error:', error);this.delete(key);returnnull;}}delete(key){ localStorage.removeItem(this.prefix + key);}clear(){const keys = Object.keys(localStorage); keys.forEach(key=>{if(key.startsWith(this.prefix)){ localStorage.removeItem(key);}});}// 获取所有缓存键getAllKeys(){return Object.keys(localStorage).filter(key=> key.startsWith(this.prefix)).map(key=> key.replace(this.prefix,''));}}// 使用示例const localCache =newLocalStorageCache();// 缓存用户设置 localCache.set('userSettings',{theme:'dark',language:'zh-CN'},24*60*60*1000);// 24小时const settings = localCache.get('userSettings'); console.log(settings);// { theme: 'dark', language: 'zh-CN' }

2. SessionStorage

// SessionStorage 缓存classSessionStorageCache{constructor(prefix ='session_'){this.prefix = prefix;}set(key, value){const data ={ value,timestamp: Date.now()}; sessionStorage.setItem(this.prefix + key,JSON.stringify(data));}get(key){const item = sessionStorage.getItem(this.prefix + key);if(!item)returnnull;try{const data =JSON.parse(item);return data.value;}catch(error){ console.error('Parse error:', error);this.delete(key);returnnull;}}delete(key){ sessionStorage.removeItem(this.prefix + key);}clear(){const keys = Object.keys(sessionStorage); keys.forEach(key=>{if(key.startsWith(this.prefix)){ sessionStorage.removeItem(key);}});}}// 使用示例const sessionCache =newSessionStorageCache();// 缓存表单数据 sessionCache.set('formData',{name:'张三',email:'[email protected]'});// 页面刷新后数据仍然存在(会话期间)const formData = sessionCache.get('formData');

3. IndexedDB

// IndexedDB 封装classIndexedDBCache{constructor(dbName, storeName){this.dbName = dbName;this.storeName = storeName;this.db =null;}asyncinit(){returnnewPromise((resolve, reject)=>{const request = indexedDB.open(this.dbName,1); request.onerror=()=>reject(request.error); request.onsuccess=()=>{this.db = request.result;resolve(this.db);}; request.onupgradeneeded=(event)=>{const db = event.target.result;if(!db.objectStoreNames.contains(this.storeName)){const store = db.createObjectStore(this.storeName,{keyPath:'key'}); store.createIndex('timestamp','timestamp',{unique:false});}};});}asyncset(key, value, ttl =0){const data ={ key, value,timestamp: Date.now(), ttl };returnnewPromise((resolve, reject)=>{const transaction =this.db.transaction([this.storeName],'readwrite');const store = transaction.objectStore(this.storeName);const request = store.put(data); request.onerror=()=>reject(request.error); request.onsuccess=()=>resolve(request.result);});}asyncget(key){returnnewPromise((resolve, reject)=>{const transaction =this.db.transaction([this.storeName],'readonly');const store = transaction.objectStore(this.storeName);const request = store.get(key); request.onerror=()=>reject(request.error); request.onsuccess=()=>{const data = request.result;if(!data){resolve(null);return;}// 检查是否过期if(data.ttl && Date.now()- data.timestamp > data.ttl){this.delete(key);resolve(null);return;}resolve(data.value);};});}asyncdelete(key){returnnewPromise((resolve, reject)=>{const transaction =this.db.transaction([this.storeName],'readwrite');const store = transaction.objectStore(this.storeName);const request = store.delete(key); request.onerror=()=>reject(request.error); request.onsuccess=()=>resolve(request.result);});}asyncclear(){returnnewPromise((resolve, reject)=>{const transaction =this.db.transaction([this.storeName],'readwrite');const store = transaction.objectStore(this.storeName);const request = store.clear(); request.onerror=()=>reject(request.error); request.onsuccess=()=>resolve(request.result);});}asyncgetAll(){returnnewPromise((resolve, reject)=>{const transaction =this.db.transaction([this.storeName],'readonly');const store = transaction.objectStore(this.storeName);const request = store.getAll(); request.onerror=()=>reject(request.error); request.onsuccess=()=>resolve(request.result);});}}// 使用示例const idbCache =newIndexedDBCache('MyApp','apiCache');await idbCache.init();// 缓存大量数据await idbCache.set('user:123',{profile:{name:'张三',age:25},posts:[...],// 大数组preferences:{...}},3600000);// 1小时const userData =await idbCache.get('user:123');

缓存策略详解

1. Cache First

// Cache First 策略:先查缓存,缓存没有再请求网络asyncfunctioncacheFirst(request, cacheName){const cache =await caches.open(cacheName);const cachedResponse =await cache.match(request);if(cachedResponse){return cachedResponse;}const networkResponse =awaitfetch(request);if(networkResponse.ok){ cache.put(request, networkResponse.clone());}return networkResponse;}// 适用场景:静态资源(CSS、JS、图片)const cssResponse =awaitcacheFirst('/static/css/main.css','assets-cache');

2. Network First

// Network First 策略:先请求网络,失败则使用缓存asyncfunctionnetworkFirst(request, cacheName, timeout =5000){const cache =await caches.open(cacheName);try{// 设置超时const networkPromise =fetch(request);const timeoutPromise =newPromise((resolve, reject)=>{setTimeout(()=>reject(newError('Timeout')), timeout);});const response =await Promise.race([networkPromise, timeoutPromise]);if(response.ok){ cache.put(request, response.clone());}return response;}catch(error){// 网络失败,使用缓存const cachedResponse =await cache.match(request);if(cachedResponse){return cachedResponse;}throw error;}}// 适用场景:API 数据const userData =awaitnetworkFirst('/api/user/123','api-cache');

3. Stale While Revalidate

// Stale While Revalidate 策略:返回缓存,同时后台更新asyncfunctionstaleWhileRevalidate(request, cacheName){const cache =await caches.open(cacheName);const cachedResponse =await cache.match(request);const fetchPromise =fetch(request).then(response=>{if(response.ok){ cache.put(request, response.clone());}return response;}).catch(error=>{ console.error('Fetch failed:', error);returnnull;});// 立即返回缓存,同时后台更新return cachedResponse || fetchPromise;}// 适用场景:新闻文章、博客内容const articles =awaitstaleWhileRevalidate('/api/articles','articles-cache');

4. Cache Only

// Cache Only 策略:只从缓存获取asyncfunctioncacheOnly(request, cacheName){const cache =await caches.open(cacheName);const cachedResponse =await cache.match(request);if(!cachedResponse){thrownewError('No cached response found');}return cachedResponse;}// 适用场景:离线页面const offlinePage =awaitcacheOnly('/offline.html','offline-cache');

5. Network Only

// Network Only 策略:只从网络获取asyncfunctionnetworkOnly(request){returnawaitfetch(request);}// 适用场景:登录、支付等敏感操作const loginResponse =awaitnetworkOnly('/api/login',{method:'POST',body:JSON.stringify(credentials)});

策略选择决策树

需要缓存的资源 | ├─ 静态资源(CSS、JS、图片) → Cache First │ └─ 长期缓存(1年)+ 版本控制 │ ├─ API 数据(用户信息、商品列表) → Network First │ └─ 短期缓存(5分钟)+ 错误回退 │ ├─ 频繁更新的内容(新闻、博客) → Stale While Revalidate │ └─ 显示缓存 + 后台更新 │ ├─ 离线页面 → Cache Only │ └─ 预缓存关键页面 │ └─ 敏感操作(登录、支付) → Network Only └─ 不缓存,确保数据最新 

实际应用场景

1. API 数据缓存

用户信息缓存
classUserCache{constructor(){this.cache =newLRUCache(50);this.apiCache =newLocalStorageCache('user_');}asyncgetUser(userId, forceRefresh =false){const cacheKey =`user:${userId}`;// 强制刷新或内存缓存中没有if(!forceRefresh){const cached =this.cache.get(cacheKey);if(cached){ console.log('从内存缓存获取用户:', userId);return cached;}}// 检查本地存储缓存const localCached =this.apiCache.get(cacheKey);if(localCached &&!forceRefresh){ console.log('从本地存储获取用户:', userId);this.cache.set(cacheKey, localCached);return localCached;}// 请求 APItry{const response =awaitfetch(`/api/user/${userId}`);if(!response.ok)thrownewError('Failed to fetch');const userData =await response.json();// 更新缓存this.cache.set(cacheKey, userData);this.apiCache.set(cacheKey, userData,10*60*1000);// 10分钟return userData;}catch(error){ console.error('Failed to fetch user:', error);// 返回本地缓存(如果有)if(localCached){return localCached;}throw error;}}updateUser(userId, userData){const cacheKey =`user:${userId}`;this.cache.set(cacheKey, userData);this.apiCache.set(cacheKey, userData,10*60*1000);}clearUser(userId){const cacheKey =`user:${userId}`;this.cache.delete(cacheKey);this.apiCache.delete(cacheKey);}}const userCache =newUserCache();// 使用const user =await userCache.getUser('123'); userCache.updateUser('123',{...user,name:'新名称'});
分页数据缓存
classPaginatedCache{constructor(){this.cache =newMap();// key: `${url}:${page}`, value: { data, timestamp }this.cacheTime =5*60*1000;// 5分钟}asyncgetPage(url, page, params ={}){const cacheKey =`${url}:${page}:${JSON.stringify(params)}`;const cached =this.cache.get(cacheKey);if(cached && Date.now()- cached.timestamp <this.cacheTime){return cached.data;}const queryParams =newURLSearchParams({ page,...params });const response =awaitfetch(`${url}?${queryParams}`);if(!response.ok)thrownewError('Failed to fetch');const data =await response.json();this.cache.set(cacheKey,{ data,timestamp: Date.now()});return data;}invalidatePage(url, page){// 删除指定页的缓存for(const key ofthis.cache.keys()){if(key.startsWith(`${url}:${page}:`)){this.cache.delete(key);}}}invalidateUrl(url){// 删除指定 URL 的所有缓存for(const key ofthis.cache.keys()){if(key.startsWith(`${url}:`)){this.cache.delete(key);}}}}const paginatedCache =newPaginatedCache();// 使用const products =await paginatedCache.getPage('/api/products',1,{category:'electronics',sort:'price'});

2. 图片资源缓存

图片预加载
classImageCache{constructor(maxCache =50){this.cache =newMap();// key: url, value: { img, timestamp }this.maxCache = maxCache;}preloadImage(url){returnnewPromise((resolve, reject)=>{// 检查缓存const cached =this.cache.get(url);if(cached){resolve(cached.img);return;}const img =newImage(); img.onload=()=>{// 添加到缓存this.cache.set(url,{ img,timestamp: Date.now()});// 如果缓存超过限制,删除最旧的if(this.cache.size >this.maxCache){const firstKey =this.cache.keys().next().value;this.cache.delete(firstKey);}resolve(img);}; img.onerror = reject; img.src = url;});}getImage(url){const cached =this.cache.get(url);return cached ? cached.img :null;}clear(){this.cache.clear();}}const imageCache =newImageCache();// 预加载图片functionpreloadImages(urls){return Promise.all(urls.map(url=> imageCache.preloadImage(url)));}// 使用preloadImages(['/images/hero.jpg','/images/product1.jpg','/images/product2.jpg']).then(()=>{ console.log('所有图片预加载完成');});
图片懒加载
classLazyImageLoader{constructor(){this.imageCache =newImageCache(100);this.observer =null;this.init();}init(){// Intersection Observer 实现懒加载if('IntersectionObserver'in window){this.observer =newIntersectionObserver((entries)=>{ entries.forEach(entry=>{if(entry.isIntersecting){const img = entry.target;const src = img.dataset.src;this.loadImage(img, src);this.observer.unobserve(img);}});},{rootMargin:'50px'// 提前50px开始加载});}}asyncloadImage(img, src){try{const image =awaitthis.imageCache.preloadImage(src); img.src = image.src; img.classList.remove('lazy');}catch(error){ console.error('Failed to load image:', error); img.classList.add('error');}}observe(img){if(this.observer){this.observer.observe(img);}else{// 降级方案:直接加载const src = img.dataset.src;this.loadImage(img, src);}}}const lazyImageLoader =newLazyImageLoader();// HTML// <img alt="示例">// <img alt="示例">// JavaScript document.querySelectorAll('img.lazy').forEach(img=>{ lazyImageLoader.observe(img);});

3. 页面组件缓存

React 组件缓存
// 使用 React.memo 和 useMemo 缓存组件const ExpensiveComponent = React.memo(({ data, filter })=>{const filteredData =useMemo(()=>{return data.filter(item=> item.category === filter);},[data, filter]);return(<div>{filteredData.map(item=>(<div key={item.id}>{item.name}</div>))}</div>);});// 使用 useCallback 缓存函数functionParentComponent(){const[count, setCount]=useState(0);const handleClick =useCallback(()=>{setCount(prev=> prev +1);},[]);return(<div><button onClick={handleClick}>点击 {count} 次</button><ExpensiveComponent data={expensiveData} filter="active"/></div>);}
动态组件缓存
classComponentCache{constructor(){this.cache =newMap();}asyncloadComponent(importFunc){const modulePath = importFunc.toString();// 检查缓存if(this.cache.has(modulePath)){returnthis.cache.get(modulePath);}// 动态加载组件const module =awaitimportFunc();const Component = module.default;// 缓存组件this.cache.set(modulePath, Component);return Component;}clear(){this.cache.clear();}}const componentCache =newComponentCache();// 动态加载路由组件const routes =[{path:'/user',component:()=>import('./UserComponent')},{path:'/product',component:()=>import('./ProductComponent')}];// 渲染路由functionrenderRoute(route){ componentCache.loadComponent(route.component).then(Component=>{ ReactDOM.render(<Component />, document.getElementById('root'));});}

性能优化实践

1. 缓存分层策略

// 多层缓存架构classMultiLayerCache{constructor(){this.l1Cache =newMap();// 内存缓存,最快this.l2Cache =newLocalStorageCache('l2_');// 本地存储this.l3Cache =newIndexedDBCache('MyApp','l3');// IndexedDB}asyncget(key){// L1 缓存if(this.l1Cache.has(key)){returnthis.l1Cache.get(key);}// L2 缓存const l2Data =this.l2Cache.get(key);if(l2Data){this.l1Cache.set(key, l2Data);return l2Data;}// L3 缓存const l3Data =awaitthis.l3Cache.get(key);if(l3Data){this.l1Cache.set(key, l3Data);this.l2Cache.set(key, l3Data);return l3Data;}returnnull;}asyncset(key, value, ttl =0){// 设置所有层级this.l1Cache.set(key, value);this.l2Cache.set(key, value, ttl);awaitthis.l3Cache.set(key, value, ttl);}asyncdelete(key){this.l1Cache.delete(key);this.l2Cache.delete(key);awaitthis.l3Cache.delete(key);}clear(){this.l1Cache.clear();this.l2Cache.clear();this.l3Cache.clear();}}const multiLayerCache =newMultiLayerCache();

2. 缓存预热

// 缓存预热classCacheWarmer{constructor(cache){this.cache = cache;}asyncwarmUp(config){ console.log('开始缓存预热...');const promises = config.map(async({ key, fetcher, ttl })=>{try{const data =awaitfetcher();awaitthis.cache.set(key, data, ttl); console.log(`预热成功: ${key}`);}catch(error){ console.error(`预热失败: ${key}`, error);}});await Promise.all(promises); console.log('缓存预热完成');}}// 配置预热数据const warmer =newCacheWarmer(multiLayerCache); warmer.warmUp([{key:'user:123',fetcher:()=>fetch('/api/user/123').then(r=> r.json()),ttl:10*60*1000},{key:'menu-items',fetcher:()=>fetch('/api/menu').then(r=> r.json()),ttl:30*60*1000},{key:'config',fetcher:()=>fetch('/api/config').then(r=> r.json()),ttl:60*60*1000}]);

3. 缓存压缩

// 缓存数据压缩import LZString from'lz-string';classCompressedCache{constructor(cache){this.cache = cache;}asyncset(key, value, ttl =0){// 压缩数据const compressed = LZString.compress(JSON.stringify(value));awaitthis.cache.set(key, compressed, ttl);}asyncget(key){const compressed =awaitthis.cache.get(key);if(!compressed)returnnull;try{const decompressed = LZString.decompress(compressed);returnJSON.parse(decompressed);}catch(error){ console.error('Failed to decompress:', error);returnnull;}}}const compressedCache =newCompressedCache(multiLayerCache);

4. 缓存统计

// 缓存统计classCacheStats{constructor(){this.hits =0;this.misses =0;this.size =0;}recordHit(){this.hits++;}recordMiss(){this.misses++;}gethitRate(){const total =this.hits +this.misses;return total >0?(this.hits / total)*100:0;}getStats(){const total =this.hits +this.misses;return{hits:this.hits,misses:this.misses, total,hitRate:this.hitRate.toFixed(2)+'%',size:this.size };}reset(){this.hits =0;this.misses =0;}}// 带统计的缓存classStatsCache{constructor(cache){this.cache = cache;this.stats =newCacheStats();}asyncget(key){const value =awaitthis.cache.get(key);if(value){this.stats.recordHit();}else{this.stats.recordMiss();}return value;}asyncset(key, value, ttl){returnthis.cache.set(key, value, ttl);}getStats(){returnthis.stats.getStats();}resetStats(){this.stats.reset();}}const statsCache =newStatsCache(multiLayerCache);// 定期输出统计信息setInterval(()=>{ console.log('缓存统计:', statsCache.getStats());},60000);

缓存失效与更新

1. TTL(Time To Live)

// TTL 管理classTTLCache{constructor(){this.cache =newMap();this.timeouts =newMap();}set(key, value, ttl){// 设置缓存this.cache.set(key, value);// 清除之前的定时器if(this.timeouts.has(key)){clearTimeout(this.timeouts.get(key));}// 设置新的定时器if(ttl >0){const timeoutId =setTimeout(()=>{this.delete(key);}, ttl);this.timeouts.set(key, timeoutId);}}get(key){returnthis.cache.get(key);}delete(key){this.cache.delete(key);const timeoutId =this.timeouts.get(key);if(timeoutId){clearTimeout(timeoutId);this.timeouts.delete(key);}}clear(){// 清除所有定时器for(const timeoutId ofthis.timeouts.values()){clearTimeout(timeoutId);}this.timeouts.clear();this.cache.clear();}}

2. 版本控制

// 基于版本的缓存失效classVersionedCache{constructor(){this.cache =newMap();this.version ='v1';}setVersion(newVersion){if(this.version !== newVersion){this.version = newVersion;this.clear();// 版本变化时清除所有缓存}}set(key, value, ttl =0){const versionedKey =`${this.version}:${key}`;this.cache.set(versionedKey,{ value, ttl,timestamp: Date.now()});}get(key){const versionedKey =`${this.version}:${key}`;const item =this.cache.get(versionedKey);if(!item)returnnull;if(item.ttl && Date.now()- item.timestamp > item.ttl){this.delete(key);returnnull;}return item.value;}delete(key){const versionedKey =`${this.version}:${key}`;this.cache.delete(versionedKey);}clear(){this.cache.clear();}}// 使用版本控制const versionedCache =newVersionedCache();// 应用更新时升级版本 versionedCache.setVersion('v2');

3. 基于依赖的失效

// 基于依赖图的缓存失效classDependencyCache{constructor(){this.cache =newMap();this.dependents =newMap();// key -> Set<dependent keys>}set(key, value, dependencies =[]){// 设置缓存this.cache.set(key, value);// 更新依赖关系 dependencies.forEach(dep=>{if(!this.dependents.has(dep)){this.dependents.set(dep,newSet());}this.dependents.get(dep).add(key);});}invalidate(key){// 删除缓存this.cache.delete(key);// 删除依赖它的缓存const deps =this.dependents.get(key);if(deps){ deps.forEach(depKey=>{this.cache.delete(depKey);});this.dependents.delete(key);}}get(key){returnthis.cache.get(key);}}// 使用示例const depCache =newDependencyCache();// 设置缓存和依赖关系 depCache.set('user:123',{name:'张三'},['settings:123']); depCache.set('settings:123',{theme:'dark'});// settings 变化时,user:123 也会失效 depCache.invalidate('settings:123');

4. 手动失效

// 手动失效策略classCacheInvalidator{constructor(){this.patterns =newMap();// pattern -> handler}// 注册失效模式register(pattern, handler){this.patterns.set(pattern, handler);}// 失效缓存asyncinvalidate(cacheKey){for(const[pattern, handler]ofthis.patterns.entries()){if(this.matchPattern(pattern, cacheKey)){awaithandler(cacheKey);}}}matchPattern(pattern, key){// 简单的 glob 模式匹配const regex =newRegExp(pattern.replace('*','.*'));return regex.test(key);}}// 配置失效规则const invalidator =newCacheInvalidator(); invalidator.register('user:*',(key)=>{ console.log('失效用户缓存:', key); cache.delete(key);}); invalidator.register('product:*',(key)=>{ console.log('失效商品缓存:', key); cache.delete(key);});// 使用await invalidator.invalidate('user:123');

常见问题与解决方案

1. 缓存穿透

// 问题:请求不存在的数据,导致缓存失效// 解决:缓存空值或使用布隆过滤器classAntiPenetrationCache{constructor(cache){this.cache = cache;this.nullCache =newSet();// 缓存空值的 keythis.nullTTL =5*60*1000;// 空值缓存5分钟}asyncget(key){// 检查是否是已知不存在的 keyif(this.nullCache.has(key)){returnnull;}const value =awaitthis.cache.get(key);// 如果数据不存在,缓存空值if(value ===null){this.nullCache.add(key);setTimeout(()=>{this.nullCache.delete(key);},this.nullTTL);}return value;}asyncset(key, value){if(value ===null){this.nullCache.add(key);}else{this.nullCache.delete(key);}awaitthis.cache.set(key, value);}}

2. 缓存雪崩

// 问题:大量缓存同时失效// 解决:添加随机延迟、使用分布式锁classAvalancheProtectionCache{constructor(cache){this.cache = cache;this.locks =newSet();}asyncget(key, fetcher, ttl =300000){const value =awaitthis.cache.get(key);if(value !==null){return value;}// 检查是否已经有其他请求在加载if(this.locks.has(key)){// 等待其他请求完成returnnewPromise((resolve)=>{const checkLock =setInterval(()=>{if(!this.locks.has(key)){clearInterval(checkLock);this.get(key, fetcher, ttl).then(resolve);}},100);});}// 获取分布式锁this.locks.add(key);try{const data =awaitfetcher();// 添加随机 TTL 避免同时失效const randomTTL = ttl + Math.random()* ttl *0.1;// 最多额外10%awaitthis.cache.set(key, data, randomTTL);return data;}finally{this.locks.delete(key);}}}

3. 缓存击穿

// 问题:热点数据失效时大量请求直达数据库// 解决:互斥锁classCacheBreakdownProtection{constructor(cache){this.cache = cache;this.locks =newMap();}asyncget(key, fetcher, ttl =300000){let value =awaitthis.cache.get(key);if(value !==null){return value;}// 获取锁(使用分布式锁更好)const lockKey =`lock:${key}`;const lockValue = Date.now().toString();if(this.locks.has(lockKey)){// 等待锁释放returnnewPromise((resolve, reject)=>{const timeout =setTimeout(()=>{this.locks.delete(lockKey);reject(newError('Lock timeout'));},5000);const checkLock =setInterval(()=>{if(!this.locks.has(lockKey)){clearInterval(checkLock);clearTimeout(timeout);this.get(key, fetcher, ttl).then(resolve).catch(reject);}},100);});}// 加锁this.locks.set(lockKey, lockValue);try{const data =awaitfetcher();awaitthis.cache.set(key, data, ttl);return data;}finally{// 释放锁this.locks.delete(lockKey);}}}

4. 数据一致性

// 数据一致性保证classConsistentCache{constructor(cache){this.cache = cache;this.versionMap =newMap();// key -> version}asyncset(key, value, ttl =0){const version = Date.now();const data ={ value, version };awaitthis.cache.set(key, data, ttl);this.versionMap.set(key, version);}asyncget(key){const data =awaitthis.cache.get(key);if(!data)returnnull;// 检查版本是否是最新的const currentVersion =this.versionMap.get(key);if(data.version !== currentVersion){returnnull;// 版本过期}return data.value;}// 标记数据为已更新invalidate(key){this.versionMap.set(key, Date.now());}}

最佳实践

1. 缓存设计原则

// 缓存设计检查清单constCACHE_CHECKLIST={// 1. 明确缓存对象identifyCacheTargets:()=>{// - 静态资源(CSS、JS、图片)// - API 数据(用户信息、列表数据)// - 计算结果(复杂计算、排序、筛选)// - 页面组件(React/Vue 组件)},// 2. 选择合适策略selectStrategy:()=>{// - 静态资源:Cache First// - 频繁更新:Network First// - 展示优先:Stale While Revalidate// - 敏感数据:Network Only},// 3. 设置合理 TTLsetTTL:()=>{// - 用户信息:5-10分钟// - 静态资源:1年// - 配置数据:1小时// - 列表数据:1-5分钟},// 4. 缓存失效策略invalidationStrategy:()=>{// - 基于时间的失效// - 基于版本的失效// - 基于事件的失效// - 手动失效},// 5. 监控和统计monitoring:()=>{// - 命中率统计// - 缓存大小监控// - 性能指标// - 错误率统计}};

2. 缓存最佳实践

// 缓存实践指南classCacheBestPractices{// 1. 缓存键命名规范staticgenerateCacheKey(base, params){return`${base}:${JSON.stringify(params)}`;}// 2. 缓存数据大小限制staticisCacheableSize(size, maxSize =1024*1024){return size <= maxSize;}// 3. 压缩大数据staticasynccompress(data){if(typeof data ==='string'){return LZString.compress(data);}returnJSON.stringify(data);}// 4. 批量操作优化staticasyncbatchGet(cache, keys){const promises = keys.map(key=> cache.get(key));return Promise.all(promises);}staticasyncbatchSet(cache, items){const promises = items.map(({ key, value, ttl })=> cache.set(key, value, ttl));return Promise.all(promises);}// 5. 预加载常用数据staticasyncpreload(cache, configs){const promises = configs.map(({ key, fetcher, ttl })=> cache.get(key).then(value=>{if(value)return value;returnfetcher().then(data=>{ cache.set(key, data, ttl);return data;});}));return Promise.all(promises);}}

3. 性能优化技巧

// 性能优化技巧classCachePerformanceOptimization{// 1. 异步缓存staticasyncasyncCache(cache, key, fetcher, ttl){const cached = cache.get(key);if(cached)return cached;// 启动后台加载fetcher().then(data=>{ cache.set(key, data, ttl);}).catch(error=>{ console.error('Async cache load failed:', error);});// 返回占位数据或 nullreturnnull;}// 2. 缓存预取staticprefetch(cache, urls){ urls.forEach(url=>{// 空闲时预取if('requestIdleCallback'in window){requestIdleCallback(()=>{ cache.get(url);});}else{setTimeout(()=> cache.get(url),0);}});}// 3. 缓存分片staticshardCache(cache, shardCount =10){const shardedCaches = Array.from({length: shardCount },()=>newMap());return{get(key){const shardIndex =this.getShardIndex(key);return shardedCaches[shardIndex].get(key);},set(key, value, ttl){const shardIndex =this.getShardIndex(key); shardedCaches[shardIndex].set(key, value);},getShardIndex(key){let hash =0;for(let i =0; i < key.length; i++){ hash =(hash <<5)- hash + key.charCodeAt(i); hash |=0;}return Math.abs(hash)% shardCount;}};}// 4. 缓存统计和优化建议staticanalyzeCache(cache){const stats = cache.getStats();const suggestions =[];if(stats.hitRate <0.8){ suggestions.push('命中率低于80%,建议调整缓存策略');}if(stats.size >100){ suggestions.push('缓存项过多,考虑使用 LRU 策略');}return{ stats, suggestions };}}

4. 安全性考虑

// 缓存安全classSecureCache{constructor(cache){this.cache = cache;}// 1. 加密敏感数据asyncsetSecure(key, value, password, ttl =0){const encrypted =awaitthis.encrypt(value, password);awaitthis.cache.set(key, encrypted, ttl);}asyncgetSecure(key, password){const encrypted =awaitthis.cache.get(key);if(!encrypted)returnnull;returnawaitthis.decrypt(encrypted, password);}asyncencrypt(data, password){// 使用 Web Crypto API 加密const encoder =newTextEncoder();const dataBuffer = encoder.encode(JSON.stringify(data));const passwordBuffer = encoder.encode(password);// 导入密钥const key =await crypto.subtle.importKey('raw', passwordBuffer,{name:'PBKDF2'},false,['deriveKey']);// 生成盐const salt = crypto.getRandomValues(newUint8Array(16));// 派生密钥const derivedKey =await crypto.subtle.deriveKey({name:'PBKDF2',salt: salt,iterations:100000,hash:'SHA-256'}, key,{name:'AES-GCM',length:256},false,['encrypt']);// 加密数据const iv = crypto.getRandomValues(newUint8Array(12));const encryptedBuffer =await crypto.subtle.encrypt({name:'AES-GCM',iv: iv }, derivedKey, dataBuffer );// 返回加密后的数据(包含盐和 IV)return{salt: Array.from(salt),iv: Array.from(iv),data: Array.from(newUint8Array(encryptedBuffer))};}asyncdecrypt(encryptedData, password){// 解密实现const{ salt, iv, data }= encryptedData;// ... 解密逻辑returnJSON.parse(decryptedString);}// 2. 防止缓存投毒validateCacheData(data){// 验证数据结构if(typeof data !=='object'|| data ===null){returnfalse;}// 检查敏感字段if(data.password || data.token || data.secret){ console.warn('Sensitive data in cache');returnfalse;}returntrue;}// 3. 访问控制asyncgetWithAccessCheck(key, accessToken){// 验证访问令牌if(!this.validateAccessToken(accessToken)){thrownewError('Access denied');}const data =awaitthis.cache.get(key);if(!this.validateCacheData(data)){thrownewError('Invalid cache data');}return data;}}

总结

缓存技术总结

缓存是前端性能优化的核心技术之一,它通过在多个层级存储数据副本来提高访问速度和减少网络请求。

主要缓存技术
  1. HTTP 缓存:浏览器层面的缓存,控制静态资源的缓存行为
  2. Service Worker 缓存:强大的缓存控制能力,支持离线应用
  3. 内存缓存:最快的缓存方式,适用于临时数据
  4. 状态管理缓存:应用层面的数据缓存,提升用户体验
  5. 浏览器存储缓存:本地持久化存储,跨会话数据共享
关键策略
  • Cache First:适用于静态资源
  • Network First:适用于频繁更新的数据
  • Stale While Revalidate:平衡性能和新鲜度
  • Cache Only:适用于离线页面
  • Network Only:适用于敏感数据
最佳实践
  1. 合理选择缓存层级:多层缓存架构
  2. 设置合适的 TTL:根据数据特性调整过期时间
  3. 监控缓存性能:跟踪命中率和性能指标
  4. 处理缓存问题:防止穿透、雪崩、击穿
  5. 保障数据安全:加密敏感数据,验证缓存内容

Read more

主流AI绘图工具PK:ComfyUI、Stable Diffusion与Z-Image-Turbo全面评测

主流AI绘图工具PK:ComfyUI、Stable Diffusion与Z-Image-Turbo全面评测 随着生成式AI技术的迅猛发展,AI图像生成已从实验室走向大众创作。在众多开源和商业化工具中,ComfyUI、Stable Diffusion WebUI(SD WebUI) 与近期由阿里通义团队推出的 Z-Image-Turbo WebUI 成为开发者和创作者关注的焦点。三者定位不同、架构各异,在易用性、性能表现和扩展能力上各有千秋。 本文将从核心架构、使用体验、生成质量、部署成本、适用场景五大维度,对这三款主流AI绘图工具进行深度对比评测,并结合真实运行截图与参数调优建议,帮助你做出更精准的技术选型决策。 技术背景与选型动因 AI图像生成模型自Stable Diffusion发布以来,经历了从“能画”到“快画”再到“可控画”的演进。用户需求也从简单的文生图,逐步扩展至高质量输出、低延迟响应、可复现控制、流程自动化等工程化要求。 在此背景下: - Stable Diffusion WebUI 凭借成熟生态成为入门首选;

Neo4j图谱可视化-告别单调灰色、掌握色彩定制的艺术

Neo4j图谱可视化-告别单调灰色、掌握色彩定制的艺术

摘要 本文旨在系统地介绍在 Neo4j 中为知识图谱定制颜色的多种方法与最佳实践。从最基础的手动界面操作,到通过修改数据结构实现持久化着色,再到基于节点属性的高级动态着色技巧,本文将为读者提供一套完整的图谱可视化解决方案,帮助读者将复杂的数据网络转化为直观、清晰、富有洞察力的彩色图谱。 引言:当知识图谱遇上 “色盲” 当您第一次在 Neo4j Browser 中执行查询,满怀期待地切换到图形视图时,可能会遇到一个令人沮丧的场景:一个由无数灰色节点和线条构成的杂乱网络。这种单调的视觉呈现,使得数据中蕴含的丰富结构和关系模式难以被快速识别,极大地削弱了知识图谱作为数据分析工具的价值。 幸运的是,Neo4j Browser 提供了强大而灵活的样式定制功能。通过为不同类型的节点和关系应用恰当的颜色,我们可以将数据的内在逻辑和层次结构直观地呈现出来,让知识图谱真正 “活” 起来,成为洞察数据的有力武器。 本文将从核心原理出发,详细讲解三种主流的颜色定制方法,并通过具体的医药和情感分析实例,帮助您掌握这门 “图谱着色” 的艺术。 核心概念:颜色与 “标签(Label)” 的绑定

无人机相关法律法规全体系梳理

无人机相关法律法规全体系梳理 随着无人机产业的高速发展,我国已构建起以“国家行政法规为核心、部门规章为支撑、地方细则为补充”的无人机法律体系,覆盖无人机生产、登记、飞行、监管全链条。本梳理结合2024-2025年最新法规修订内容,聚焦不同主体(个人/企业)的合规要点,明确权利与义务边界。 一、国家层面核心行政法规(基础遵循) 此类法规具有最高法律效力,是无人机管理的根本依据,核心包括《无人驾驶航空器飞行管理暂行条例》及关联法律修订内容。 1. 《无人驾驶航空器飞行管理暂行条例》(2024年1月1日实施) 我国首部专门规范无人机的行政法规,共6章63条,确立“分类管理、安全优先”的核心原则,覆盖无人机全生命周期管理。核心条款如下: (1)无人机分类与适航管理 按性能指标将无人机分为五类,差异化设定适航要求,是后续所有管理的基础: 类别 核心指标(空机重量/最大起飞重量) 适航许可要求 生产标注要求 微型 <0.25千克

TWIST2——全身VR遥操控制:采集人形全身数据后,可训练视觉base的自主策略(基于视觉观测预测全身关节位置)

TWIST2——全身VR遥操控制:采集人形全身数据后,可训练视觉base的自主策略(基于视觉观测预测全身关节位置)

前言 我司内部在让机器人做一些行走-操作任务时,不可避免的需要全身遥操机器人采集一些任务数据,而对于全身摇操控制,目前看起来效果比较好的,并不多 * 之前有个CLONE(之前本博客内也解读过),但他们尚未完全开源 * 于此,便关注到了本文要解读的TWIST2,其核心创新是:无动捕下的全身控制 PS,如果你也在做loco-mani相关的工作,欢迎私我你的一两句简介,邀你加入『七月:人形loco-mani(行走-操作)』交流群 第一部分 TWIST2:可扩展、可移植且全面的人形数据采集系统 1.1 引言与相关工作 1.1.1 引言 如TWIST2原论文所说,现有的人形机器人远程操作系统主要分为三大类: 全身控制,直接跟踪人体姿态,包括手臂、躯干和腿部在内的所有关节以统一方式进行控制(如 HumanPlus [12],TWIST [1] ———— TWIST的介绍详见此文《TWIST——基于动捕的全身遥操模仿学习:教师策略RL训练,学生策略结合RL和BC联合优化(可训练搬箱子)》 部分全身控制,