成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

Axios 功能擴展之Axios-Retry 源碼閱讀筆記

開發 前端
通過對 axios-retry 這一周下載量 100w+ 的三方庫來學習下其功能設計,工具庫項目的發包策略,并借此拋磚引玉,以提升我們的編碼設計能力!

[[436191]]

前兩天分析了 Axios 的源碼設計🔗,其中的攔截器(interceptor)為擴展 Axios 留下了入口,在工作中我們也時常會擴展 Axios,例如:取消重復請求、權限驗證、失敗重試等。

那么如何設計實現一個好的攔截器來擴展 Axios?

通過對 axios-retry 這一周下載量 100w+ 的三方庫來學習下其功能設計,工具庫項目的發包策略,并借此拋磚引玉,以提升我們的編碼設計能力!

  • Github: https://github.com/softonic/axios-retry
  • NPM: https://www.npmjs.com/package/axios-retry

一、工具庫的 package.json 寫法

看一個模塊的源碼,首先先看 README.md 和 package.json 文件。

參考如上,未來我們也應該在開發工具庫的時候需要關注以下字段:

  • files:在發包的時候發布將 es、lib 兩文件夾,以及 index.js 和 index.d.ts 文件。
  • typings:TypeScript 類型定義文件,用于在 TypeScript 編碼環境下智能類型提示,該字段亦可寫作 types。
  • main:主要入口文件,表明在項目中引入當前庫時候,默認指向的文件是 index.js
  • module:并非官方字段,打包工具約定的如果有該字段,則在例如 Rollup 和 Webpack 打包時,處理指定導入我們庫的 ESM 版本的文件路徑。
  • exports:提供了一種方法來為不同的環境和 JavaScript 風格顯示聲明如何引入模塊,同時限制對其內部部分的訪問,該字段提案來自:Bare Module Specifier Resolution in node.js[1]

通過依賴字段以及 scripts 字段:

開發依賴和使用依賴

可以得知,當前項目直接使用 Babel 作為打包編譯工具,通過執行 npm run release 發包,并結合 npm scripts 的 pre 和 post 執行生命周期依次執行完成如下任務:

npm run release 執行的任務流程(原文鏈接可查看大圖)

更多關于 package.json 字段的功能/作用描述,可參考 package.json - NPM[2]

二、源碼分析

根據 package.json 文件中關于“發包”命令相關解讀之后,可以得知 ./es/ 文件夾下的 index.mjs 為功能實現文件。

2.1 為什么是 .mjs 文件名后綴

Node.js 原本的模塊系統是 CommonJs (使用 require 和 module.exports 語法)。

自 Node.js 創建后, ECMAScript 模塊系統 (使用 import 和 export 語法) 已經變成一種標準,并且 Node.js 已經加入并實現支持 ES 模塊系統。

Node.js 將 *.cjs 文件當作 CommonJS 模塊, *.mjs 文件當作 ECMAScript 模塊。它會將 .js 文件視為項目的默認模塊系統,除非 package.json 聲明 "type": "module",否則就是 CommonJS。

2.2 axios-retry 的用法

axios-retry 對外導出 axiosRetry() 方法:

注入攔截器

通過對 axios 單例添加“攔截器”,來擴展實現自動重試網絡請求功能。

axios-retry 主要接受兩個參數,第一個是 axios 實例,第二個是 axios-retry 的配置 defaultOptions:

  1. defaultOptions: { 
  2.     retries?: number; // 自動重試次數 
  3.     shouldResetTimeout?: boolean; // 是否重置“超時時間” 
  4.     retryCondition?: Function; // 重試的條件,可傳入自定義判斷函數 
  5.     retryDelay?: Function;  // 重試請求的間隔時間的函數 

功能配置看起來挺完善的,難怪那么受歡迎。

2.3 請求攔截器設計&實現

在請求攔截器中會做狀態初始化,更新請求次數:

  1. axios.interceptors.request.use((config) => { 
  2.   const currentState = getCurrentState(config); 
  3.   // 設置上次請求的時間 
  4.   // 思考🤔:為什么不放到 getCurrentState() 函數內一起設置? 
  5.   currentState.lastRequestTime = Date.now(); 
  6.   return config; 
  7. }); 
  1. /** 
  2.  * 初始化并返回給定“請求”和“配置”的重試狀態 
  3.  * @param  {AxiosRequestConfig} config 
  4.  * @return {Object} 
  5.  */ 
  6. function getCurrentState(config) { 
  7.   // 從 config 獲取狀態 
  8.   const currentState = config[namespace] || {}; 
  9.   // 記錄當前請求的次數 
  10.   currentState.retryCount = currentState.retryCount || 0; 
  11.   // 更新/寫入 config 中當前請求狀態 
  12.   config[namespace] = currentState; 
  13.   return currentState; 

通過對 axios config 注入 axios-retry 字段作為存儲請求狀態的字段,在 axios 的請求執行鏈中,可隨時從 axios config 中拿到當前請求狀態。

另外,我們看到請求攔截器中并沒有設置 reject 的函數,或許這里可以添加針對 reject 響應函數,用于在發生請求異常后,可直接不需要重試請求,因為錯誤的請求配置必然是無意義的網絡請求,重試請求也是無意義的,直接中斷退出請求執行鏈。

關于退出 Promise 執行鏈,提供幾個參考的討論:

  • 從如何停掉 Promise 鏈說起[3]
  • Promise 的鏈式調用與中止[4]

2.4 響應攔截器設計&實現

在攔截器中,只響應 reject 函數,也就是只在 axios 響應階段發生錯誤(拋出異常)的時候,才會執行當前攔截器。

  1. axios.interceptors.response.use(null, async (error) => { 
  2.   const { config } = error; 
  3.  
  4.   // 讀取不到 config,則退出,可能是一些其他異常情況 
  5.   // 例如:主動取消請求,是直接拋出的錯誤 
  6.   if (!config) { 
  7.     return Promise.reject(error); 
  8.   } 
  9.  
  10.   // 從 defaultOptions 讀取并設置默認值 
  11.   const { 
  12.     retries = 3, // 默認自動重試 3 次 
  13.     retryCondition = isNetworkOrIdempotentRequestError, 
  14.     retryDelay = noDelay, 
  15.     shouldResetTimeout = false 
  16.   } = getRequestOptions(config, defaultOptions); 
  17.  
  18.   const currentState = getCurrentState(config); 
  19.  
  20.   // 判斷是否需要重試 
  21.   if (await shouldRetry(retries, retryCondition, currentState, error)) { 
  22.     // 需要的話,則 currentState 需要更新重試次數 
  23.     currentState.retryCount += 1; 
  24.     const delay = retryDelay(currentState.retryCount, error); 
  25.  
  26.     // Axios 合并默認配置失敗,因為循環結構 
  27.     // 參考 issue: https://github.com/mzabriskie/axios/issues/370 
  28.     fixConfig(axios, config); 
  29.  
  30.     // shouldResetTimeout 默認為 false 
  31.     // 根據實際請求的時間,并比較 config.timeout,選最大值來設置的超時時間 
  32.     if (!shouldResetTimeout && config.timeout && currentState.lastRequestTime) { 
  33.       const lastRequestDuration = Date.now() - currentState.lastRequestTime; 
  34.       // Minimum 1ms timeout (passing 0 or less to XHR means no timeout) 
  35.       // 設置超時時間最小 1ms(認為 <= 0 的 XHR 請求不算超時) 
  36.       config.timeout = Math.max(config.timeout - lastRequestDuration - delay, 1); 
  37.     } 
  38.  
  39.     config.transformRequest = [(data) => data]; 
  40.      
  41.     // 常見的 Promise 延時的寫法(sleep) 
  42.     // 重新發起請求,調用 axios(config) 
  43.     // 因為無論何種類型請求,都會被標準化為 axios(config) 
  44.     // 在應用層 axios.prototye.request 做了兼容轉換 
  45.     return new Promise((resolve) => setTimeout(() => resolve(axios(config)), delay)); 
  46.   } 
  47.  
  48.   return Promise.reject(error); 
  49. }); 

總結

這是針對 axios 源碼分析文章的一個補充,作為常見對于 axios 的功能擴展,失敗重試 axios-retry 算是一個比較好的例子,可以作為之后擴展 axios 功能的一個模板。

另外,axios-retry 中通過 Babel 直接打包,以及其借助 NPM scripts 的生命周期,將測試、更新版本,打包構建、發布、Git push串聯起來,也是值得借鑒之處。

在文中有提到,在請求攔截器中可以,添加針對“發起網絡請求”前的錯誤處理,如果發生錯誤,直接中斷重試過程,避免錯誤的請求多次發起,節省計算資源,可以動手嘗試實現一下。

當然,是否需要重試請求,在響應攔截器中通過 shouldRetry() 函數來保證了,但在 axios 請求執行鏈上,響應攔截器始終是需要通過發起網絡請求(dispachRequest() 事件)后才會執行,所以這個嘗試還是可以研究研究🧐,對于搞懂 Promise 執行鏈大有裨益。

參考資料

[1]Bare Module Specifier Resolution in node.js:

https://github.com/jkrems/proposal-pkg-exports/

[2]package.json - NPM:

https://docs.npmjs.com/cli/v8/configuring-npm/package-json

[3]從如何停掉 Promise 鏈說起:

https://github.com/xieranmaya/blog/issues/5

[4]Promise 的鏈式調用與中止:

https://cnodejs.org/topic/58385d4927d001d606ac197d

 

責任編輯:姜華 來源: DYBOY
相關推薦

2021-11-19 07:54:59

Axios網絡源碼

2013-12-24 10:05:04

memcached

2018-07-30 16:31:00

javascriptaxioshttp

2014-07-03 15:40:09

Apache Spar

2022-02-14 10:16:22

Axios接口HTTP

2021-09-04 23:27:58

Axios源碼流程

2025-03-25 08:40:00

前端開發Axios

2020-12-03 08:14:45

Axios核心Promise

2021-11-17 08:24:47

Vue3 插件Vue應用

2021-09-09 10:23:08

GinNetHttp

2021-07-27 14:50:15

axiosHTTP前端

2016-09-20 10:15:49

LaravelPHPContainer

2021-06-02 05:41:48

項目實踐Axiosaxios二次封裝

2023-05-05 00:08:37

AxiosAlova開發

2021-04-22 05:37:14

Axios 開源項目HTTP 攔截器

2020-10-20 09:12:57

axios核心原理

2016-09-20 10:26:25

LaravelPHPMiddleware

2012-03-01 09:38:43

GoogleChrome

2013-12-31 10:32:57

移動閱讀多看閱讀PDF

2022-07-05 16:03:29

電源管理子系統鴻蒙
點贊
收藏

51CTO技術棧公眾號

主站蜘蛛池模板: 男女免费网站 | 久久精品一区二区三区四区 | 97caoporn国产免费人人 | 欧美手机在线 | 亚洲视频欧美视频 | 亚洲视频中文字幕 | 国产成人免费一区二区60岁 | 偷拍自拍第一页 | 国产欧美在线 | 久久国产一区二区三区 | 亚洲精品白浆高清久久久久久 | 99精品免费 | 久久午夜剧场 | 人人澡人人爱 | 久久尤物免费一区二区三区 | 成人福利网站 | 免费人成在线观看网站 | 欧美黄色一区 | 中文字字幕在线中文乱码范文 | 中文字幕一区二区三区不卡在线 | 在线观看www | 91精品在线播放 | 亚洲网站在线播放 | 日韩精品一区二区三区在线播放 | 天天久久 | 日韩免费网站 | 成年人网站免费 | 亚洲精品一| 午夜在线观看视频 | 午夜视频导航 | 免费的色网站 | 久久久久黄| 亚洲精品美女视频 | av大片 | 日本污视频 | 九九伊人sl水蜜桃色推荐 | 成人在线视频网站 | 国产免费一级片 | 无码一区二区三区视频 | 欧美456| 亚洲精品在线视频 |