1、背景
在一些項目中,有時候會出現不同子產品重複請求大量相同API接口的情況,特别是在一些功能相似的背景管理頁面中。
以下面這幾個頁面為例,每次進入頁面都需要請求等大量重複的下拉框資料,下拉框資料短時間内改動不大,但也不能在前端使用靜态資料,是以可以考慮在前端進行資料緩存,避免重複請求API。
2、 實作思路
主要有以下3個步驟:
- 初次擷取資料,從伺服器中請求資料;
- 建立一個映射表,将下拉框資料儲存起來,并同時記錄該資料的時間戳;
- 後續再次請求時,首先從映射表中查找資料,如果可以查到資料且資料沒過期,則直接使用資料,否則重新從伺服器中擷取資料;
3、具體實作
3.1 、初次擷取資料
以下代碼中,首先調用 getLocalData 方法查找緩存,如果沒找到緩存,就向伺服器請求資料(this.$api.task.getCateListAll),擷取到資料後用 setLocalData 方法把資料緩存起來。
// 任務類型下拉框資料
// 首先判斷是否有緩存
if (!this.getLocalData('cate')) {
/** 初次請求資料 */
await this.$api.task.getCateListAll().then((res) => {
this.m_taskPropOption.cate = this.$u.array.arrToSelect(res.data); // 使用資料
this.m_taskPropDict.cate = this.$u.array.arrToObj(this.m_taskPropOption.cate, "id"); // 使用資料
this.setLocalData('cate'); // 緩存資料
});
}
3.2 、建立映射表,緩存資料
緩存資料主要使用了浏覽器的API localStorage,如下面代碼中 setLocalData 方法,每次從伺服器擷取資料後,根據 key 将資料儲存在 localStorage 中,并且同時記錄時間戳,記錄時間戳是為了後面檢查緩存資料的過期時間:
/** 設定緩存 - 建立映射表 */
setLocalData(key) {
// 緩存資料
localStorage.setItem(`task_${key}_option`, jsON.stringify(this.m_taskPropOption[key])); // 緩存資料
localStorage.setItem(`task_${key}_dict`, jsON.stringify(this.m_taskPropDict[key])); // 緩存資料
localStorage.setItem(`task_${key}_timestamp`, Date.now()); // 記錄時間戳
}
3.3 、查找緩存資料
根據方法 getLocalData ,首先根據 key 從 localStorage 中查找緩存的時間戳(時間戳是在緩存資料時一起儲存的,如果有時間戳,則表示有緩存資料),如果有緩存時間并且判斷緩存時間未過期,則進一步從緩存中擷取資料給到程式使用:
/** 擷取緩存 - 查找映射表 并 檢查過期時間 */
getLocalData(key) {
let storageTimestamp = localStorage.getItem(`task_${key}_timestamp`);
let expires = 1000 * 3600; // 有效時間
let timestamp = Date.now(); // 目前時間戳
// 從緩存中取資料(1h内資料)
if (storageTimestamp && (timestamp - storageTimestamp) < expires) {
let option = localStorage.getItem(`task_${key}_option`); // 從緩存中拿到資料給程式使用
let dict = localStorage.getItem(`task_${key}_dict`); // 從緩存中拿到資料給程式使用
this.m_taskPropOption[key] = JSON.parse(option);
this.m_taskPropDict[key] = JSON.parse(dict);
return true;
}
return false;
}
3.4 、實作效果
使用緩存前進入頁面:
使用緩存後進入頁面:
由上圖可以看出,使用緩存前進入頁面需要請求7個api接口,而緩存了資料之後,進入頁面隻需要請求3個接口即可,确實起到了減少了請求接口數量的效果。
4、方案的不足之處及改善
本方案首要的不足在于前端無法準确獲知資料庫中資料的更新時間。目前暫時設定了緩存時間 expires = 3600 * 1000 ms,也就是說1h内資料被更新了的話,前端顯示的依然是緩存的舊資料,這一點暫時沒想到改善方法。
此外,緩存使用了 localStorage API。localStorage 的特點是隻要不手動清除,資料會一直儲存在浏覽器端,這樣使用者就沒有辦法清除緩存,要改善這一點的話可以換一個全局對象(vuex)來儲存資料,隻要頁面重新整理的話,緩存的資料會被清除。