前端数据缓存机制是提升应用性能、减少网络请求、优化用户体验的关键技术手段。以下是前端常见的数据缓存方案及其实现细节,涵盖浏览器缓存、本地存储、内存缓存等多种策略:
通过 HTTP 协议头控制缓存,适用于静态资源(如 JS、CSS、图片)和接口响应。
Cache-Control: max-age=3600 # 资源有效期 1 小时(优先级高)
Expires: Wed, 21 Oct 2024 07:28:00 GMT # 过期时间(HTTP/1.0)
# 服务器返回标识
ETag: "33a64df551425fcc55e4d42a148795d9"
Last-Modified: Wed, 21 Oct 2024 07:28:00 GMT
# 浏览器请求时携带标识
If-None-Match: "33a64df551425fcc55e4d42a148795d9"
If-Modified-Since: Wed, 21 Oct 2024 07:28:00 GMT
适用于存储结构化数据,容量约 5~10MB,分为 localStorage
和 sessionStorage
。
// 存储数据(注意:只能存字符串)
localStorage.setItem('user', JSON.stringify({ name: 'Alice' }));
// 读取数据
const user = JSON.parse(localStorage.getItem('user'));
// 删除数据
localStorage.removeItem('user');
async function fetchWithCache(url, cacheKey, ttl = 3600) {
const cachedData = localStorage.getItem(cacheKey);
if (cachedData) {
const { data, timestamp } = JSON.parse(cachedData);
if (Date.now() - timestamp < ttl * 1000) {
return data; // 返回有效缓存
}
}
const response = await fetch(url);
const newData = await response.json();
localStorage.setItem(cacheKey, JSON.stringify({
data: newData,
timestamp: Date.now()
}));
return newData;
}
适用于存储大量结构化数据(支持索引、事务),容量可达数百 MB。
// 打开数据库
const request = indexedDB.open('myDB', 1);
request.onupgradeneeded = (event) => {
const db = event.target.result;
const store = db.createObjectStore('apiCache', { keyPath: 'url' });
store.createIndex('timestamp', 'timestamp', { unique: false });
};
// 存储数据
function saveToIndexedDB(url, data) {
const transaction = db.transaction('apiCache', 'readwrite');
const store = transaction.objectStore('apiCache');
store.put({ url, data, timestamp: Date.now() });
}
// 查询数据
async function getFromIndexedDB(url) {
return new Promise((resolve) => {
const transaction = db.transaction('apiCache', 'readonly');
const store = transaction.objectStore('apiCache');
const request = store.get(url);
request.onsuccess = (e) => resolve(e.target.result?.data);
});
}
适用于单页应用(SPA)中短期数据缓存,随页面刷新失效。
const memoryCache = new Map();
async function fetchWithMemoryCache(url) {
if (memoryCache.has(url)) {
return memoryCache.get(url);
}
const response = await fetch(url);
const data = await response.json();
memoryCache.set(url, data);
return data;
}
class LRUCache {
constructor(maxSize = 100) {
this.cache = new Map();
this.maxSize = maxSize;
}
get(key) {
if (!this.cache.has(key)) return null;
const value = this.cache.get(key);
this.cache.delete(key);
this.cache.set(key, value);
return value;
}
set(key, value) {
if (this.cache.size >= this.maxSize) {
const oldestKey = this.cache.keys().next().value;
this.cache.delete(oldestKey);
}
this.cache.set(key, value);
}
}
实现离线缓存和网络请求拦截,适合 PWA 应用。
// sw.js
self.addEventListener('fetch', (event) => {
if (event.request.url.includes('/api/')) {
event.respondWith(
caches.match(event.request).then((cachedResponse) => {
return cachedResponse || fetch(event.request).then((response) => {
const clone = response.clone();
caches.open('api-cache-v1').then((cache) => {
cache.put(event.request, clone);
});
return response;
});
})
);
}
});
import { useQuery } from 'react-query';
function UserProfile() {
const { data } = useQuery('userData', () =>
fetch('/api/user').then(res => res.json()), {
staleTime: 5 * 60 * 1000, // 5分钟缓存有效期
cacheTime: 30 * 60 * 1000 // 30分钟保留时间
});
// ...
}
import useSWR from 'swr';
function Profile() {
const { data } = useSWR('/api/user', fetcher, {
revalidateOnFocus: false, // 窗口聚焦时不刷新
dedupingInterval: 60000 // 60秒内相同请求去重
});
// ...
}
user-v2
)pull-to-refresh
)sessionStorage
替代 localStorage
存储会话数据场景 | 推荐方案 | 容量 | 有效期 |
---|---|---|---|
静态资源 | HTTP 强缓存 | 无上限 | 长期 |
低频变动的接口数据 | localStorage |
5~10MB | 自定义 |
大量结构化数据 | IndexedDB | 数百MB | 长期 |
实时性要求高的数据 | 内存缓存 | 内存限制 | 页面会话 |
离线优先应用 | Service Worker | 50~250MB | 自定义 |
通过合理设计缓存机制,可显著提升前端性能,但在实际应用中需平衡以下关系:
✅ 新鲜度 vs 性能
✅ 存储空间 vs 用户体验
✅ 开发成本 vs 维护成本