<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          【JS】625- Axios 如何緩存請求數據?

          共 9764字,需瀏覽 20分鐘

           ·

          2021-04-14 12:44

          Axios 如何取消重復請求? 這篇文章中,阿寶哥介紹了在 Axios 中如何取消重復請求及 CancelToken 的工作原理。本文將介紹在 Axios 中如何通過增強默認適配器來緩存請求數據。那么為什么要緩存請求數據呢?這是因為在緩存未失效時,我們可以直接使用已緩存的數據,而不需發(fā)起請求從服務端獲取數據,這樣不僅可以減少 HTTP 請求而且還能減少等待時間從而提高用戶體驗。

          因為本文將使用 Axios 提供的默認適配器來實現緩存請求數據的功能,所以如果你對 Axios 適配器還不熟悉的話,建議先閱讀 77.9K 的 Axios 項目有哪些值得借鑒的地方 這篇文章。為了讓大家能夠更好地理解后續(xù)的內容,我們先來看一下整體的流程圖:

          上圖中藍色部分的工作流程,就是本文的重點。接下來,阿寶哥將從如何設計緩存開始,帶大家一起來開發(fā)緩存請求數據的功能。

          一、如何設計緩存

          在計算中,緩存是一個高速數據存儲層,其中存儲了數據子集,且通常是 短暫性 存儲,這樣日后再次請求該數據時,速度要比訪問數據的主存儲位置快。通過緩存,你可以高效地重用之前檢索或計算的數據。了解完緩存的作用之后,我們來設計緩存的 API:

          • get(key):從緩存中獲取指定 key 對應的值;
          • delete(key):從緩存中刪除指定 key 對應的值;
          • clear():清空已緩存的數據;
          • set(key, value, maxAge):保存鍵值對,同時支持設置緩存的最大時間,即 maxAge 單位為毫秒。

          基于上述的緩存 API,我們可以實現一個簡單的緩存功能,具體代碼如下所示:

          const MemoryCache = {
            data: {},
            set(key, value, maxAge) { // 保存數據
              this.data[key] = {
                maxAge: maxAge || 0,
                value,
                nowDate.now(),
               };
            },
            get(key) { // 從緩存中獲取指定 key 對應的值。
              const cachedItem = this.data[key];
              if (!cachedItem) return null;
              const isExpired = Date.now() - cachedItem.now > cachedItem.maxAge;
              isExpired && this.delete(key);
              return isExpired ? null : cachedItem.value;
            },
            delete(key) { // 從緩存中刪除指定 key 對應的值。
              return delete this.data[key];
            },
            clear() { // 清空已緩存的數據。
              this.data = {};
            },
          };

          其實除了自定義緩存對象之外,你也可以使用成熟的第三方庫,比如 lru-cache。

          LRU 緩存淘汰算法就是一種常用策略。LRU 的全稱是 Least Recently Used,也就是說我們認為最近使用過的數據應該是是「有用的」,很久都沒用過的數據應該是無用的,內存滿了就優(yōu)先刪那些很久沒用過的數據。

          二、如何增強默認適配器

          Axios 引入了適配器,使得它可以同時支持瀏覽器和 Node.js 環(huán)境。對于瀏覽器環(huán)境來說,它通過封裝 XMLHttpRequest API 來發(fā)送 HTTP 請求,而對于 Node.js 環(huán)境來說,它通過封裝 Node.js 內置的 http 和 https 模塊來發(fā)送 HTTP 請求。

          在介紹如何增強默認適配器之前,我們先來回顧一下 Axios 完整請求的流程:

          了解完 Axios 完整請求的流程之后,我們再來看一下 Axios 內置的 xhrAdapter 適配器,它被定義在 lib/adapters/xhr.js 文件中:

          // lib/adapters/xhr.js
          module.exports = function xhrAdapter(config{
            return new Promise(function dispatchXhrRequest(resolve, reject{
              var requestData = config.data;
              var requestHeaders = config.headers;

              var request = new XMLHttpRequest();
              // 省略大部分代碼
              var fullPath = buildFullPath(config.baseURL, config.url);
              request.open(config.method.toUpperCase(), buildURL(fullPath, config.params, config.paramsSerializer), true);
              // Set the request timeout in MS
              request.timeout = config.timeout;

              // Listen for ready state
              request.onreadystatechange = function handleLoad({ ... }

              // Send the request
              request.send(requestData);
            });
          };

          很明顯 xhrAdapter 適配器是一個函數對象,它接收一個 config 參數并返回一個 Promise 對象。而在 xhrAdapter 適配器內部,最終會使用 XMLHttpRequest API 來發(fā)送 HTTP 請求。為了實現緩存請求數據的功能,我們就可以考慮通過高階函數來增強 xhrAdapter 適配器的功能。

          2.1 定義輔助函數

          2.1.1 定義 generateReqKey 函數

          在增強 xhrAdapter 適配器之前,我們先來定義一個 generateReqKey 函數,該函數用于根據當前請求的信息,生成請求 Key;

          function generateReqKey(config{
            const { method, url, params, data } = config;
            return [method, url, Qs.stringify(params), Qs.stringify(data)].join("&");
          }

          通過 generateReqKey 函數生成的請求 key,將作為緩存項的 key,而對應的 value 就是默認 xhrAdapter 適配器返回的 Promise 對象。

          2.1.2 定義 isCacheLike 函數

          isCacheLike 函數用于判斷傳入的 cache 參數是否實現了前面定義的 Cache API,利用該函數,我們允許用戶為每個請求自定義 Cache 對象。

          function isCacheLike(cache{
           return !!(cache.set && cache.get && cache.delete && cache.clear  
            && typeof cache.get === 'function' && typeof cache.set === 'function' 
              && typeof cache.delete === 'function' && typeof cache.clear === 'function'
            );
          }

          2.2 定義 cacheAdapterEnhancer 函數

          為了讓用戶能夠更靈活地控制數據緩存的功能,我們定義了一個 cacheAdapterEnhancer 函數,該函數支持兩個參數:

          • adapter:預增強的 Axios 適配器對象;
          • options:緩存配置對象,該對象支持 4 個屬性,分別用于配置不同的功能:
            • maxAge:全局設置緩存的最大時間;
            • enabledByDefault:是否啟用緩存,默認為 true;
            • cacheFlag:緩存標志,用于配置請求 config 對象上的緩存屬性;
            • defaultCache:用于設置使用的緩存對象。

          了解完 cacheAdapterEnhancer 函數的參數之后,我們來看一下該函數的具體實現:

          function cacheAdapterEnhancer(adapter, options{
            const { maxAge, enabledByDefault = true,
              cacheFlag = "cache", defaultCache = MemoryCache,
            } = options;
            
            return (config) => {
              const { url, method, params, forceUpdate } = config;
              let useCache = config[cacheFlag] !== undefined && config[cacheFlag] !== null
                  ? config[cacheFlag]
                  : enabledByDefault;
                if (method === "get" && useCache) {
                  const cache = isCacheLike(useCache) ? useCache : defaultCache;
                  let requestKey = generateReqKey(config);  // 生成請求Key
                  let responsePromise = cache.get(requestKey); // 從緩存中獲取請求key對應的響應對象
                  if (!responsePromise || forceUpdate) { // 緩存未命中/失效或強制更新時,則重新請求數據
                     responsePromise = (async () => {
                       try {
                         return await adapter(config);  // 使用默認的xhrAdapter發(fā)送請求
                       } catch (reason) {
                           cache.delete(requestKey);
                           throw reason;
                          }
                     })();
                     cache.set(requestKey, responsePromise, maxAge);  // 保存請求返回的響應對象
                     return responsePromise; // 返回已保存的響應對象
                 }
                 return responsePromise;
               }
               return adapter(config); // 使用默認的xhrAdapter發(fā)送請求
             };
          }

          以上的代碼并不會復雜,核心的處理邏輯如下圖所示:

          2.3 使用 cacheAdapterEnhancer 函數

          2.3.1 創(chuàng)建 Axios 對象并配置 adapter 選項
          const http = axios.create({
            baseURL"https://jsonplaceholder.typicode.com",
            adapter: cacheAdapterEnhancer(axios.defaults.adapter, {
              enabledByDefaultfalse// 默認禁用緩存
              maxAge5000// 緩存時間為5s
            }),
          });
          2.3.2 使用 http 對象發(fā)送請求
          // 使用緩存
          async function requestWithCache({
            const response = await http.get("/todos/1", { cachetrue });
            console.dir(response);
          }

          // 不使用緩存
          async function requestWithoutCache({
            const response = await http.get("/todos/1", { cachefalse });
            console.dir(response);
          }

          其實 cache 屬性除了支持布爾值之外,我們可以配置實現 Cache API 的緩存對象,具體的使用示例如下所示:

          const customCache = { get() {/*...*/}, set() {/*...*/}, delete() {/*...*/}, clear() {/*...*/}};
                
          async function requestForceUpdate({
            const response = await http.get("/todos/1", {
              cache: customCache,
              forceUpdatetrue,
            });
            console.dir(response);
          }

          好了,如何通過增強 xhrAdapter 適配器來實現 Axios 緩存請求數據的功能已經介紹完了。由于完整的示例代碼內容比較多,阿寶哥就不放具體的代碼了。感興趣的小伙伴,可以訪問以下地址瀏覽示例代碼。

          完整的示例代碼:https://gist.github.com/semlinker/b8a7bd5a0a16c2d04011c2c4a8167fbd

          三、總結

          本文介紹了在 Axios 中如何緩存請求數據及如何設計緩存對象,基于文中定義的 cacheAdapterEnhancer 函數,你可以輕松地擴展緩存的功能。在后續(xù)的文章中,阿寶哥將會介紹在 Axios 中如何實現請求重試功能,感興趣的小伙伴不要錯過喲。另外,如果你對 Axios 如何取消重復請求感興趣,可以閱讀 Axios 如何取消重復請求? 這篇文章。

          四、參考資源

          瀏覽 45
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          評論
          圖片
          表情
          推薦
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  国产熟妇 码AV | 亚洲免费日本精品在线观看 | 国产成人无码综合亚洲日韩不卡 | 高清无码在线观看av | 日韩无码成人影片 |