快取是提升 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 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 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
}
參考檔案
鼓勵一下
如果你覺得這篇文章不錯,希望可以給與我一些鼓勵,在我的 github 部落格下幫忙 star 一下。