緩存是提升 web 應用程序有效方法之一,尤其是用户受限於網速的情況下。提升系統的響應能力,降低網絡的消耗。當然,內容越接近於用户,則緩存的速度就會越快,緩存的有效性則會越高。
之前個人寫過 前端 api 請求緩存方案。介紹的了內存中的緩存以及過期邏輯。後續也寫過 手寫一個前端存儲工具庫,該工具利用了適配器處理了不同的存儲介質(內存,IndexedDB, localStorage 等)。
不過,在某些特定場景下緩存還需要優化,例如:用户需要在登錄或者填寫表單時需要通過某些接口獲取必要數據,而這些接口是由第三方平台提供的。這些接口可能會出現錯誤或超時的情況。如果當前數據有很強實時性,開發者就必須重試或者聯繫第三方平台來處理對應的錯誤。如果數據的實時性不強,當前就可以使用本地緩存。
一般來説,當獲取時效性緩存時候,我們會檢查並刪除當前數據。代碼簡寫如下所示:
// 緩存對應的的模塊以及功能
const EXTRA_INFO_CACHE_KEY = 'xxx.xxx.xxx';
// 緩存時長為 7 天
const CACHE_TIME = 7 * 24 * 60 * 60 * 1000;
const getCachedExtraInfo = () => {
const cacheStr = localStorage.getItem(`${EXTRA_INFO_CACHE_KEY}.${userId}`);
if (!cacheStr) {
return null;
}
let cache = null;
try {
cache = JSON.parse(cacheStr);
} catch () {
return null;
}
if (!cache) {
return null;
}
// 緩存過期了,直接返回 null
if ((cache.expiredTime ?? 0) < new Date().getTime()) {
return null;
}
return cache.data;
}
const getExtraInfo = () => {
const cacheData = getCachedExtraInfo();
if (cacheData) {
return Promise.resolve(cacheData);
}
return getExtraInfoApi().then(res => {
localStorage.setItem(`${EXTRA_INFO_CACHE_KEY}.${userId}`, {
data: res,
expiredTime: (new Data()).getTime() + CACHE_TIME,
});
return res;
});
}
如果這時候接口出現了訪問錯誤問題,很多數據到期的用户就無法正常使用功能了,這時候添加重試功能可能會解決某些錯誤。這時候我們先不考慮重試的邏輯。
考慮到絕大部份用户對應數據不會進行修改的情況下,對應代碼就可以不進行數據刪除。而是返回超時標記。
const EXTRA_INFO_CACHE_KEY = 'xxx.xxx.xxx';
const CACHE_TIME = 7 * 24 * 60 * 60 * 1000;
const getCachedExtraInfo = () => {
const cacheStr = localStorage.getItem(`${EXTRA_INFO_CACHE_KEY}.${userId}`);
if (!cacheStr) {
return null;
}
let cache = null;
try {
cache = JSON.parse(cacheStr)
} catch () {
return null;
}
if (!cache) {
return null;
}
if ((cache.expiredTime ?? 0) < new Date().getTime()) {
return {
data: cache.data,
// 數據已經超時了
isOverTime: true,
};
}
return {
data: cache.data,
// 數據沒有超時
isOverTime: false,
};
}
const getExtraInfo = () => {
const cacheInfo = getCachedExtraInfo();
// 數據沒有超時才返回對應數據
if (cacheInfo && !cacheInfo.isOverTime) {
return Promise.resolve(cacheInfo.data);
}
return getExtraInfoApi().then(res => {
localStorage.setItem(`${EXTRA_INFO_CACHE_KEY}.${userId}`, {
data: res,
expiredTime: (new Data()).getTime() + CACHE_TIME,
});
return res;
}).catch(err => {
// 有數據,才返回,否則繼續拋出錯誤
if (cacheInfo) {
return cacheInfo.data;
}
throw err;
})
}
這樣的話,我們可以保證絕大多數用户是可以繼續正常使用的。但如果對應的接口不穩定,會讓用户等待很長時間才能繼續使用。
這時候開發者可以考慮完全拋棄異步代碼,同時減少緩存時間。
const EXTRA_INFO_CACHE_KEY = 'xxx.xxx.xxx';
// 將緩存時效減少為 5 天
const CACHE_TIME = 5 * 24 * 60 * 60 * 1000;
const getCachedExtraInfo = () => {
const cacheStr = localStorage.getItem(`${EXTRA_INFO_CACHE_KEY}.${userId}`);
if (!cacheStr) {
return null;
}
let cache = null;
try {
cache = JSON.parse(cacheStr)
} catch () {
return null;
}
if (!cache) {
return null;
}
if ((cache.expiredTime ?? 0) < new Date().getTime()) {
return {
data: cache.data,
isOverTime: true,
};
}
return {
data: cache.data,
isOverTime: false,
};
}
const getExtraInfo = () => {
const cacheInfo = getCachedExtraInfo();
// 如果超時了,就去獲取,下一次再使用即可
if (cacheInfo.isOverTime) {
getExtraInfoApi().then(res => {
localStorage.setItem(`${EXTRA_INFO_CACHE_KEY}.${userId}`, {
data: res,
expiredTime: (new Data()).getTime() + CACHE_TIME,
})
})
}
return cacheInfo.data
}
參考文檔
前端 api 請求緩存方案
手寫一個前端存儲工具庫
鼓勵一下
如果你覺得這篇文章不錯,希望可以給與我一些鼓勵,在我的 github 博客下幫忙 star 一下。
博客地址