Stories

Detail Return Return

前端持久化緩存優化 - Stories Detail

緩存是提升 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 一下。

博客地址

user avatar yinzhixiaxue Avatar zourongle Avatar xiaolei_599661330c0cb Avatar hyfhao Avatar shixiaoyuanya Avatar huanjinliu Avatar cynthia_59675eba1a2ee Avatar hsr2022 Avatar tinygeeker Avatar dengzhanyong Avatar minnanitkong Avatar zz_641473ad470bc Avatar
Favorites 34 users favorite the story!
Favorites

Add a new Comments

Some HTML is okay.