通过拦截 fetch 请求并在本地存储(如 indexeddb)中读写数据来实现缓存。具体做法是封装一个自定义函数,在发起网络请求前检查本地是否有有效缓存,若有则直接返回;若无则发起请求并将结果存入本地,同时设置过期时间以控制缓存生命周期。

如何设计带过期时间的缓存策略
使用 IndexedDB 存储包含数据和元信息的对象,通过比较当前时间与存储的 timestamp 来判断是否过期。若未过期,直接从数据库读取并解析 JSON;若已过期或不存在,则执行网络请求并更新数据库。

const DB_NAME = 'FetchCacheDB';
const STORE_NAME = 'cache';
function openDB() {
return new Promise((resolve, reject) => {
const request = indexedDB.open(DB_NAME, 1);
request.onupgradeneeded = (event) => {
const db = event.target.result;
if (!db.objectStoreNames.contains(STORE_NAME)) {
db.createObjectStore(STORE_NAME, { keyPath: 'url' });
}
};
request.onsuccess = (event) => resolve(event.target.result);
request.onerror = (event) => reject(event.target.error);
});
}
async function fetchWithCache(url, options = {}, ttl = 60000) {
const db = await openDB();
const tx = db.transaction(STORE_NAME, 'readonly');
const store = tx.objectStore(STORE_NAME);
const getRequest = store.get(url);
return new Promise((resolve, reject) => {
getRequest.onsuccess = async () => {
const cached = getRequest.result;
const now = Date.now();
if (cached && (now - cached.timestamp < ttl)) {
console.log('Hit cache for:', url);
resolve(new Response(JSON.stringify(cached.data)));
return;
}
try {
const response = await fetch(url, options);
const data = await response.json();
const putTx = db.transaction(STORE_NAME, 'readwrite');
const putStore = putTx.objectStore(STORE_NAME);
putStore.put({ url, data, timestamp: now });
resolve(response);
} catch (error) {
reject(error);
}
};
getRequest.onerror = (event) => reject(getRequest.error);
});
}如何处理并发重复请求
在缓存未命中时,将正在进行的网络请求 Promise 存入内存映射表,后续相同 URL 的请求直接复用该 Promise,避免重复发网。当请求完成或失败后,从映射表中移除该条目,确保下次请求能重新发起。
立即学习“Java免费学习笔记(深入)”;

const pendingRequests = new Map();
async function fetchWithDeduplication(url, options = {}) {
if (pendingRequests.has(url)) {
return pendingRequests.get(url);
}
const promise = fetch(url, options)
.then(async (response) => {
const data = await response.json();
// 此处可结合 IndexedDB 写入逻辑
return new Response(JSON.stringify(data));
})
.finally(() => {
pendingRequests.delete(url);
});
pendingRequests.set(url, promise);
return promise;
}基于 TTL 参数为 0 时的具体行为
当传入的 ttl 参数为 0 时,条件 (now - cached.timestamp 永远为假(除非 timestamp 为未来时间),导致每次请求都会跳过缓存判断,直接发起网络请求。这相当于禁用了缓存功能,所有请求均实时获取最新数据。


















