91超碰碰碰碰久久久久久综合_超碰av人澡人澡人澡人澡人掠_国产黄大片在线观看画质优化_txt小说免费全本

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

使用Axios攔截器解決前端并發沖突

發布時間:2021-06-23 10:39:45 來源:億速云 閱讀:351 作者:chen 欄目:web開發

這篇文章主要講解了“使用Axios攔截器解決前端并發沖突”,文中的講解內容簡單清晰,易于學習與理解,下面請大家跟著小編的思路慢慢深入,一起來研究和學習“使用Axios攔截器解決前端并發沖突”吧!

背景

并發沖突問題, 是日常開發中一個比較常見的問題。

不同用戶在較短時間間隔內變更數據,或者某一個用戶進行的重復提交操作都可能導致并發沖突。

并發場景在開發和測試階段難以排查全面,出現線上 bug 以后定位困難,因此做好并發控制是前后端開發過程中都需要重視的問題。

對于同一用戶短時間內重復提交數據的問題,前端通常可以先做一層攔截。

本文將討論前端如何利用 axios 的攔截器過濾重復請求,解決并發沖突。

一般的處理方式 — 每次發請求添加 loading

在嘗試 axios 攔截器之前,先看看我們之前業務是怎么處理并發沖突問題的:

每次用戶操作頁面上的控件(輸入框、按鈕等),向后端發送請求的時候,都給頁面對應的控件添加 loading 效果,提示正在進行數據加載,同時也阻止  loading 效果結束前用戶繼續操作控件。

這是最直接有效的方式,如果你們前端團隊成員足夠細心耐心,擁有良好的編碼習慣,這樣就可以解決大部分用戶不小心重復提交帶來的并發問題了。

更優的解決方案:axios 攔截器統一處理

項目中需要前端限制并發的場景這么多,我們當然要思考更優更省事的方案。

既然是在每次發送請求的時候進行并發控制,那如果能重新封裝下發請求的公共函數,統一處理重復請求實現自動攔截,就可以大大簡化我們的業務代碼。

項目使用的 axios 庫來發送 http 請求,axios 官方為我們提供了豐富的 API,我們來看看攔截請求需要用到的兩個核心 API:

1. interceptors

攔截器包括請求攔截器和響應攔截器,可以在請求發送前或者響應后進行攔截處理,用法如下:

// 添加請求攔截器 axios.interceptors.request.use(function (config) {   // 在發送請求之前做些什么   return config; }, function (error) {   // 對請求錯誤做些什么   return Promise.reject(error); });  // 添加響應攔截器 axios.interceptors.response.use(function (response) {     // 對響應數據做點什么     return response;   }, function (error) {     // 對響應錯誤做點什么     return Promise.reject(error);   });

2. cancel token:

調用 cancel token API 可以取消請求。

官網提供了兩種方式來構建 cancel token,我們采用這種方式:

通過傳遞一個 executor 函數到 CancelToken 的構造函數來創建 cancel  token,方便在上面的請求攔截器中檢測到重復請求可以立即執行:

const CancelToken = axios.CancelToken; let cancel;  axios.get('/user/12345', {   cancelToken: new CancelToken(function executor(c) {     // executor 函數接收一個 cancel 函數作為參數     cancel = c;   }) });  // cancel the request cancel();

本文提供的思路就是利用 axios interceptors API 攔截請求,檢測是否有多個相同的請求同時處于 pending 狀態,如果有就調用  cancel token API 取消重復的請求。

假如用戶重復點擊按鈕,先后提交了 A 和 B 這兩個完全相同(考慮請求路徑、方法、參數)的請求,我們可以從以下幾種攔截方案中選擇其一:

  • 取消 A 請求,只發出 B 請求

  • 取消 B 請求,只發出 A 請求

  • 取消 B 請求,只發出 A 請求,把收到的 A 請求的返回結果也作為 B 請求的返回結果

第三種方案需要做監聽處理增加了復雜性,結合我們實際的業務需求,最后采用了第二種方案來實現,即:

只發第一個請求。在 A 請求還處于 pending 狀態時,后發的所有與 A 重復的請求都取消,實際只發出 A 請求,直到 A  請求結束(成功/失敗)才停止對這個請求的攔截。

具體實現

1.存儲所有 pending 狀態的請求

首先我們要將項目中所有的 pending 狀態的請求存儲在一個變量中,叫它 pendingRequests,

可以通過把 axios 封裝為一個單例模式的類,或者定義全局變量,來保證  pendingRequests變量在每次發送請求前都可以訪問,并檢查是否為重復的請求。

let pendingRequests = new Map()

把每個請求的方法、url 和參數組合成一個字符串,作為標識該請求的唯一 key,同時也是 pendingRequests 對象的 key:

const requestKey = `${config.url}/${JSON.stringify(config.params)}/${JSON.stringify(config.data)}&request_type=${config.method}`;

幫助理解的小 tips:

  • 定義 pendingRequests 為 map 對象的目的是為了方便我們查詢它是否包含某個 key,以及添加和刪除 key。添加 key 時,對應的  value 可以設置用戶自定義的一些功能參數,后面擴展功能的時候會用到。

  • config 是 axios 攔截器中的參數,包含當前請求的信息

2.在請求發出前檢查當前請求是否重復

在請求攔截器中,生成上面的 requestKey,檢查 pendingRequests 對象中是否包含當前請求的 requestKey

  • 有:說明是重復的請求,cancel 掉當前請求

  • 沒有:把 requestKey 添加到 pendingRequests 對象中

因為后面的響應攔截器中還要用到當前請求的 requestKey,為了避免踩坑,最好不要再次生成。

在這一步就把 requestKey 存回 axios 攔截器的 config 參數中,后面可以直接在響應攔截器中通過  response.config.requestKey 取到。

代碼示例:

// 請求攔截器 axios.interceptors.request.use(   (config) => {     if (pendingRequests.has(requestKey)) {       config.cancelToken = new axios.CancelToken((cancel) => {         // cancel 函數的參數會作為 promise 的 error 被捕獲         cancel(`重復的請求被主動攔截: ${requestKey}`);       });     } else {       pendingRequests.set(requestKey, config);       config.requestKey = requestKey;     }     return config;   },   (error) => {     // 這里出現錯誤可能是網絡波動造成的,清空 pendingRequests 對象     pendingRequests.clear();     return Promise.reject(error);   } );

3.在請求返回后維護 pendingRequests 對象

如果請求順利走到了響應攔截器這一步,說明這個請求已經結束了 pending 狀態,那我們要把它從 pendingRequests 中除名:

axios.interceptors.response.use((response) => {   const requestKey = response.config.requestKey;   pendingRequests.delete(requestKey);   return Promise.resolve(response); }, (error) => {   if (axios.isCancel(error)) {     console.warn(error);     return Promise.reject(error);   }   pendingRequests.clear();   return Promise.reject(error); })

4.需要清空 pendingRequests 對象的場景

遇到網絡波動或者超時等情況造成請求錯誤時,需要清空原來存儲的所有 pending 狀態的請求記錄,在上面演示的代碼已經作了注釋說明。

此外,頁面切換時也需要清空之前緩存的 pendingRequests 對象,可以利用 Vue Router 的 beforeEach 鉤子:

router.beforeEach((to, from, next) => {   request.clearRequestList();   next(); });

功能擴展

1.統一處理接口報錯提示

與后端約定好接口返回數據的格式,對接口報錯的情況,可以統一在響應攔截器中添加 toast 給用戶提示,

對于特殊的不需要報錯的接口,可以設置一個參數存入 axios 攔截器的 config 參數中,過濾掉報錯提示:

// 接口返回 retcode 不為 0 時需要報錯,請求設置了 noError 為 true 則這個接口不報錯  if (   response.data.retcode &&   !response.config.noError ) {   if (response.data.message) {     Vue.prototype.$message({       showClose: true,       message: response.data.message,       type: 'error',     });   }   return Promise.reject(response.data); }

2.發送請求時給控件添加 loading 效果

上面利用 axios interceptors 過濾重復請求時,可以在控制臺拋出信息給開發者提示,在這個基礎上如果能給頁面上操作的控件添加 loading  效果就會對用戶更友好。

常見的 ui 組件庫都有提供 loading 服務,可以指定頁面上需要添加 loading 效果的控件。下面是以 element UI  為例的示例代碼:

// 給 loadingTarget 對應的控件添加 loading 效果,儲存 loadingService 實例 addLoading(config) {   if (!document.querySelector(config.loadingTarget)) return;   config.loadingService = Loading.service({     target: config.loadingTarget,   }); }  // 調用 loadingService 實例的 close 方法關閉對應元素的 loading 效果 closeLoading(config) {   config.loadingService && config.loadingService.close(); }

與上面過濾報錯方式類似,發請求的時候將元素的 class name 或 id 存入 axios 攔截器的 config 參數中,

在請求攔截器中調用 addLoading 方法, 響應攔截器中調用 closeLoading 方法,就可以實現在請求 pending 過程中指定控件(如  button) loading,請求結束后控件自動取消 loading 效果。

支持多個攔截器組合使用

簡單看下 axios interceptors 部分實現源碼可以理解,它支持定義多個 interceptors,所以只要我們定義的  interceptors 符合 Promise.then 鏈式調用的規范,還可以添加更多功能:

this.interceptors.request.forEach(function unshiftRequestInterceptors(interceptor) {   chain.unshift(interceptor.fulfilled, interceptor.rejected); });  this.interceptors.response.forEach(function pushResponseInterceptors(interceptor) {   chain.push(interceptor.fulfilled, interceptor.rejected); });  while (chain.length) {   promise = promise.then(chain.shift(), chain.shift()); }

總結

并發問題很常見,處理起來又相對繁瑣,前端解決并發沖突時,可以利用 axios 攔截器統一處理重復請求,簡化業務代碼。

同時 axios 攔截器支持更多應用,本文提供了部分常用擴展功能的實現,感興趣的同學可以繼續挖掘補充攔截器的其他用法。

感謝各位的閱讀,以上就是“使用Axios攔截器解決前端并發沖突”的內容了,經過本文的學習后,相信大家對使用Axios攔截器解決前端并發沖突這一問題有了更深刻的體會,具體使用情況還需要大家實踐驗證。這里是億速云,小編將為大家推送更多相關知識點的文章,歡迎關注!

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

龙海市| 多伦县| 海南省| 长葛市| 柏乡县| 武宣县| 江门市| 永春县| 多伦县| 乐至县| 凤城市| 山丹县| 五台县| 潢川县| 东丽区| 沈丘县| 遵义县| 宜川县| 寻甸| 台安县| 鸡泽县| 金平| 梨树县| 北票市| 中阳县| 家居| 乌鲁木齐市| 平定县| 酒泉市| 南岸区| 吉水县| 石城县| 长宁区| 黔南| 河源市| 北安市| 贡山| 万安县| 祥云县| 乐平市| 谢通门县|