前端常見的數(shù)據(jù)緩存方案及其實現(xiàn)細(xì)節(jié)
前言
前端數(shù)據(jù)緩存機(jī)制是提升應(yīng)用性能、減少網(wǎng)絡(luò)請求、優(yōu)化用戶體驗的關(guān)鍵技術(shù)手段。以下是前端常見的數(shù)據(jù)緩存方案及其實現(xiàn)細(xì)節(jié),涵蓋瀏覽器緩存、本地存儲、內(nèi)存緩存等多種策略:
1. 瀏覽器緩存(HTTP 緩存)
通過 HTTP 協(xié)議頭控制緩存,適用于靜態(tài)資源(如 JS、CSS、圖片)和接口響應(yīng)。
1.1 強(qiáng)緩存
- 原理:瀏覽器直接使用本地緩存,不向服務(wù)器發(fā)送請求。
- 實現(xiàn)方式:
Cache-Control: max-age=3600 # 資源有效期 1 小時(優(yōu)先級高) Expires: Wed, 21 Oct 2024 07:28:00 GMT # 過期時間(HTTP/1.0)
1.2 協(xié)商緩存
- 原理:瀏覽器攜帶緩存標(biāo)識詢問服務(wù)器資源是否更新。
- 實現(xiàn)方式:
# 服務(wù)器返回標(biāo)識 ETag: "33a64df551425fcc55e4d42a148795d9" Last-Modified: Wed, 21 Oct 2024 07:28:00 GMT # 瀏覽器請求時攜帶標(biāo)識 If-None-Match: "33a64df551425fcc55e4d42a148795d9" If-Modified-Since: Wed, 21 Oct 2024 07:28:00 GMT
2. Web Storage
適用于存儲結(jié)構(gòu)化數(shù)據(jù),容量約 5~10MB,分為 localStorage 和 sessionStorage。
2.1 基本使用
// 存儲數(shù)據(jù)(注意:只能存字符串)
localStorage.setItem('user', JSON.stringify({ name: 'Alice' }));
// 讀取數(shù)據(jù)
const user = JSON.parse(localStorage.getItem('user'));
// 刪除數(shù)據(jù)
localStorage.removeItem('user');
2.2 緩存策略示例
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;
}
3. IndexedDB
適用于存儲大量結(jié)構(gòu)化數(shù)據(jù)(支持索引、事務(wù)),容量可達(dá)數(shù)百 MB。
3.1 基本操作
// 打開數(shù)據(jù)庫
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 });
};
// 存儲數(shù)據(jù)
function saveToIndexedDB(url, data) {
const transaction = db.transaction('apiCache', 'readwrite');
const store = transaction.objectStore('apiCache');
store.put({ url, data, timestamp: Date.now() });
}
// 查詢數(shù)據(jù)
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);
});
}
4. 內(nèi)存緩存
適用于單頁應(yīng)用(SPA)中短期數(shù)據(jù)緩存,隨頁面刷新失效。
4.1 全局變量緩存
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;
}
4.2 LRU 緩存策略
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);
}
}
5. Service Worker 緩存
實現(xiàn)離線緩存和網(wǎng)絡(luò)請求攔截,適合 PWA 應(yīng)用。
5.1 緩存接口數(shù)據(jù)
// 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;
});
})
);
}
});
6. 現(xiàn)代框架緩存方案
6.1 React Query
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分鐘保留時間
});
// ...
}
6.2 SWR (Stale-While-Revalidate)
import useSWR from 'swr';
function Profile() {
const { data } = useSWR('/api/user', fetcher, {
revalidateOnFocus: false, // 窗口聚焦時不刷新
dedupingInterval: 60000 // 60秒內(nèi)相同請求去重
});
// ...
}
7. 緩存策略關(guān)鍵問題處理
7.1 緩存失效
- 時間戳失效:存儲數(shù)據(jù)時記錄時間戳,定期檢查過期
- 版本號控制:緩存鍵名包含版本號(如
user-v2) - 主動清除:當(dāng)數(shù)據(jù)變更時觸發(fā)緩存更新
7.2 緩存一致性
- 數(shù)據(jù)更新廣播:通過 WebSocket 或 EventSource 通知前端更新緩存
- 手動刷新機(jī)制:提供用戶手動刷新按鈕(如
pull-to-refresh)
7.3 敏感數(shù)據(jù)處理
- 避免緩存隱私數(shù)據(jù)(如 token、密碼)
- 使用
sessionStorage替代localStorage存儲會話數(shù)據(jù)
緩存方案選型建議
| 場景 | 推薦方案 | 容量 | 有效期 |
|---|---|---|---|
| 靜態(tài)資源 | HTTP 強(qiáng)緩存 | 無上限 | 長期 |
| 低頻變動的接口數(shù)據(jù) | localStorage | 5~10MB | 自定義 |
| 大量結(jié)構(gòu)化數(shù)據(jù) | IndexedDB | 數(shù)百M(fèi)B | 長期 |
| 實時性要求高的數(shù)據(jù) | 內(nèi)存緩存 | 內(nèi)存限制 | 頁面會話 |
| 離線優(yōu)先應(yīng)用 | Service Worker | 50~250MB | 自定義 |
最佳實踐
- 分層緩存:結(jié)合 HTTP 緩存 + 內(nèi)存緩存 + 持久化存儲
- 緩存降級:優(yōu)先從內(nèi)存讀取,其次本地存儲,最后網(wǎng)絡(luò)請求
- 監(jiān)控指標(biāo):跟蹤緩存命中率、存儲使用量、數(shù)據(jù)新鮮度
- 安全清理:定時清理過期緩存,避免存儲空間溢出
通過合理設(shè)計緩存機(jī)制,可顯著提升前端性能,但在實際應(yīng)用中需平衡以下關(guān)系:
? 新鮮度 vs 性能
? 存儲空間 vs 用戶體驗
? 開發(fā)成本 vs 維護(hù)成本
到此這篇關(guān)于前端常見的數(shù)據(jù)緩存方案及其實現(xiàn)細(xì)節(jié)的文章就介紹到這了,更多相關(guān)前端數(shù)據(jù)緩存機(jī)制內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Javascript在IE或Firefox下獲取鼠標(biāo)位置的代碼
由于Firefox和IE等瀏覽器之間對JS解釋的方式不一樣,F(xiàn)irefox下面獲取鼠標(biāo)位置不能夠直接使用clientX來獲取。網(wǎng)上說的一般都是觸發(fā)mousemove事件才行。我這里有兩段代碼,思路都一樣,就是風(fēng)格不同。2009-12-12
構(gòu)造函數(shù)+原型模式構(gòu)造js自定義對象(最通用)
這種方式是javascript中最通用的創(chuàng)建對象的方式,下面用示例為大家介紹下2014-05-05
Javascript立即執(zhí)行函數(shù)(IIFE)實例詳解
IIFE全拼Imdiately?Invoked?Function?Expression,是一個在定義的時候就立即執(zhí)行的JavaScript函數(shù),這篇文章主要給大家介紹了關(guān)于Javascript立即執(zhí)行函數(shù)的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),需要的朋友可以參考下2022-04-04

