前端快取API請求資料

袁藝明發表於2021-04-26

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 ,首先根據 keylocalStorage 中查詢快取的時間戳(時間戳是在快取資料時一起儲存的,如果有時間戳,則表示有快取資料),如果有快取時間並且判斷快取時間未過期,則進一步從快取中獲取資料給到程式使用:

/** 獲取快取 - 查詢對映表 並 檢查過期時間 */
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 APIlocalStorage 的特點是隻要不手動清除,資料會一直儲存在瀏覽器端,這樣使用者就沒有辦法清除快取,要改善這一點的話可以換一個全域性物件(Vuex)來儲存資料,只要頁面重新整理的話,快取的資料會被清除。
  • 此外,在系統中會有更新這些快取相關資料的模組,在這些模組中,可以在更新資料之後直接進行快取資料的清除,等到下次再請求時,程式檢查到沒有快取就會直接從伺服器請求新的資料,這一定程度改善了前端無法獲知資料跟新時間的不足。

相關文章