1. <ul id="0c1fb"></ul>

      <noscript id="0c1fb"><video id="0c1fb"></video></noscript>
      <noscript id="0c1fb"><listing id="0c1fb"><thead id="0c1fb"></thead></listing></noscript>

      99热在线精品一区二区三区_国产伦精品一区二区三区女破破_亚洲一区二区三区无码_精品国产欧美日韩另类一区

      RELATEED CONSULTING
      相關(guān)咨詢
      選擇下列產(chǎn)品馬上在線溝通
      服務(wù)時(shí)間:8:30-17:00
      你可能遇到了下面的問(wèn)題
      關(guān)閉右側(cè)工具欄

      新聞中心

      這里有您想知道的互聯(lián)網(wǎng)營(yíng)銷解決方案
      使用Axios攔截器解決前端并發(fā)沖突

      這篇文章主要講解了“使用Axios攔截器解決前端并發(fā)沖突”,文中的講解內(nèi)容簡(jiǎn)單清晰,易于學(xué)習(xí)與理解,下面請(qǐng)大家跟著小編的思路慢慢深入,一起來(lái)研究和學(xué)習(xí)“使用Axios攔截器解決前端并發(fā)沖突”吧!

      創(chuàng)新互聯(lián)公司服務(wù)項(xiàng)目包括伊通網(wǎng)站建設(shè)、伊通網(wǎng)站制作、伊通網(wǎng)頁(yè)制作以及伊通網(wǎng)絡(luò)營(yíng)銷策劃等。多年來(lái),我們專注于互聯(lián)網(wǎng)行業(yè),利用自身積累的技術(shù)優(yōu)勢(shì)、行業(yè)經(jīng)驗(yàn)、深度合作伙伴關(guān)系等,向廣大中小型企業(yè)、政府機(jī)構(gòu)等提供互聯(lián)網(wǎng)行業(yè)的解決方案,伊通網(wǎng)站推廣取得了明顯的社會(huì)效益與經(jīng)濟(jì)效益。目前,我們服務(wù)的客戶以成都為中心已經(jīng)輻射到伊通省份的部分城市,未來(lái)相信會(huì)繼續(xù)擴(kuò)大服務(wù)區(qū)域并繼續(xù)獲得客戶的支持與信任!

      背景

      并發(fā)沖突問(wèn)題, 是日常開發(fā)中一個(gè)比較常見的問(wèn)題。

      不同用戶在較短時(shí)間間隔內(nèi)變更數(shù)據(jù),或者某一個(gè)用戶進(jìn)行的重復(fù)提交操作都可能導(dǎo)致并發(fā)沖突。

      并發(fā)場(chǎng)景在開發(fā)和測(cè)試階段難以排查全面,出現(xiàn)線上 bug 以后定位困難,因此做好并發(fā)控制是前后端開發(fā)過(guò)程中都需要重視的問(wèn)題。

      對(duì)于同一用戶短時(shí)間內(nèi)重復(fù)提交數(shù)據(jù)的問(wèn)題,前端通常可以先做一層攔截。

      本文將討論前端如何利用 axios 的攔截器過(guò)濾重復(fù)請(qǐng)求,解決并發(fā)沖突。

      一般的處理方式 — 每次發(fā)請(qǐng)求添加 loading

      在嘗試 axios 攔截器之前,先看看我們之前業(yè)務(wù)是怎么處理并發(fā)沖突問(wèn)題的:

      每次用戶操作頁(yè)面上的控件(輸入框、按鈕等),向后端發(fā)送請(qǐng)求的時(shí)候,都給頁(yè)面對(duì)應(yīng)的控件添加 loading 效果,提示正在進(jìn)行數(shù)據(jù)加載,同時(shí)也阻止  loading 效果結(jié)束前用戶繼續(xù)操作控件。

      這是最直接有效的方式,如果你們前端團(tuán)隊(duì)成員足夠細(xì)心耐心,擁有良好的編碼習(xí)慣,這樣就可以解決大部分用戶不小心重復(fù)提交帶來(lái)的并發(fā)問(wèn)題了。

      更優(yōu)的解決方案:axios 攔截器統(tǒng)一處理

      項(xiàng)目中需要前端限制并發(fā)的場(chǎng)景這么多,我們當(dāng)然要思考更優(yōu)更省事的方案。

      既然是在每次發(fā)送請(qǐng)求的時(shí)候進(jìn)行并發(fā)控制,那如果能重新封裝下發(fā)請(qǐng)求的公共函數(shù),統(tǒng)一處理重復(fù)請(qǐng)求實(shí)現(xiàn)自動(dòng)攔截,就可以大大簡(jiǎn)化我們的業(yè)務(wù)代碼。

      項(xiàng)目使用的 axios 庫(kù)來(lái)發(fā)送 http 請(qǐng)求,axios 官方為我們提供了豐富的 API,我們來(lái)看看攔截請(qǐng)求需要用到的兩個(gè)核心 API:

      1. interceptors

      攔截器包括請(qǐng)求攔截器和響應(yīng)攔截器,可以在請(qǐng)求發(fā)送前或者響應(yīng)后進(jìn)行攔截處理,用法如下:

      // 添加請(qǐng)求攔截器 axios.interceptors.request.use(function (config) {   // 在發(fā)送請(qǐng)求之前做些什么   return config; }, function (error) {   // 對(duì)請(qǐng)求錯(cuò)誤做些什么   return Promise.reject(error); });  // 添加響應(yīng)攔截器 axios.interceptors.response.use(function (response) {     // 對(duì)響應(yīng)數(shù)據(jù)做點(diǎn)什么     return response;   }, function (error) {     // 對(duì)響應(yīng)錯(cuò)誤做點(diǎn)什么     return Promise.reject(error);   });

      2. cancel token:

      調(diào)用 cancel token API 可以取消請(qǐng)求。

      官網(wǎng)提供了兩種方式來(lái)構(gòu)建 cancel token,我們采用這種方式:

      通過(guò)傳遞一個(gè) executor 函數(shù)到 CancelToken 的構(gòu)造函數(shù)來(lái)創(chuàng)建 cancel  token,方便在上面的請(qǐng)求攔截器中檢測(cè)到重復(fù)請(qǐng)求可以立即執(zhí)行:

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

      本文提供的思路就是利用 axios interceptors API 攔截請(qǐng)求,檢測(cè)是否有多個(gè)相同的請(qǐng)求同時(shí)處于 pending 狀態(tài),如果有就調(diào)用  cancel token API 取消重復(fù)的請(qǐng)求。

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

      • 取消 A 請(qǐng)求,只發(fā)出 B 請(qǐng)求

      • 取消 B 請(qǐng)求,只發(fā)出 A 請(qǐng)求

      • 取消 B 請(qǐng)求,只發(fā)出 A 請(qǐng)求,把收到的 A 請(qǐng)求的返回結(jié)果也作為 B 請(qǐng)求的返回結(jié)果

      第三種方案需要做監(jiān)聽處理增加了復(fù)雜性,結(jié)合我們實(shí)際的業(yè)務(wù)需求,最后采用了第二種方案來(lái)實(shí)現(xiàn),即:

      只發(fā)第一個(gè)請(qǐng)求。在 A 請(qǐng)求還處于 pending 狀態(tài)時(shí),后發(fā)的所有與 A 重復(fù)的請(qǐng)求都取消,實(shí)際只發(fā)出 A 請(qǐng)求,直到 A  請(qǐng)求結(jié)束(成功/失敗)才停止對(duì)這個(gè)請(qǐng)求的攔截。

      具體實(shí)現(xiàn)

      1.存儲(chǔ)所有 pending 狀態(tài)的請(qǐng)求

      首先我們要將項(xiàng)目中所有的 pending 狀態(tài)的請(qǐng)求存儲(chǔ)在一個(gè)變量中,叫它 pendingRequests,

      可以通過(guò)把 axios 封裝為一個(gè)單例模式的類,或者定義全局變量,來(lái)保證  pendingRequests變量在每次發(fā)送請(qǐng)求前都可以訪問(wèn),并檢查是否為重復(fù)的請(qǐng)求。

      let pendingRequests = new Map()

      把每個(gè)請(qǐng)求的方法、url 和參數(shù)組合成一個(gè)字符串,作為標(biāo)識(shí)該請(qǐng)求的唯一 key,同時(shí)也是 pendingRequests 對(duì)象的 key:

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

      幫助理解的小 tips:

      • 定義 pendingRequests 為 map 對(duì)象的目的是為了方便我們查詢它是否包含某個(gè) key,以及添加和刪除 key。添加 key 時(shí),對(duì)應(yīng)的  value 可以設(shè)置用戶自定義的一些功能參數(shù),后面擴(kuò)展功能的時(shí)候會(huì)用到。

      • config 是 axios 攔截器中的參數(shù),包含當(dāng)前請(qǐng)求的信息

      2.在請(qǐng)求發(fā)出前檢查當(dāng)前請(qǐng)求是否重復(fù)

      在請(qǐng)求攔截器中,生成上面的 requestKey,檢查 pendingRequests 對(duì)象中是否包含當(dāng)前請(qǐng)求的 requestKey

      • 有:說(shuō)明是重復(fù)的請(qǐng)求,cancel 掉當(dāng)前請(qǐng)求

      • 沒有:把 requestKey 添加到 pendingRequests 對(duì)象中

      因?yàn)楹竺娴捻憫?yīng)攔截器中還要用到當(dāng)前請(qǐng)求的 requestKey,為了避免踩坑,最好不要再次生成。

      在這一步就把 requestKey 存回 axios 攔截器的 config 參數(shù)中,后面可以直接在響應(yīng)攔截器中通過(guò)  response.config.requestKey 取到。

      代碼示例:

      // 請(qǐng)求攔截器 axios.interceptors.request.use(   (config) => {     if (pendingRequests.has(requestKey)) {       config.cancelToken = new axios.CancelToken((cancel) => {         // cancel 函數(shù)的參數(shù)會(huì)作為 promise 的 error 被捕獲         cancel(`重復(fù)的請(qǐng)求被主動(dòng)攔截: ${requestKey}`);       });     } else {       pendingRequests.set(requestKey, config);       config.requestKey = requestKey;     }     return config;   },   (error) => {     // 這里出現(xiàn)錯(cuò)誤可能是網(wǎng)絡(luò)波動(dòng)造成的,清空 pendingRequests 對(duì)象     pendingRequests.clear();     return Promise.reject(error);   } );

      3.在請(qǐng)求返回后維護(hù) pendingRequests 對(duì)象

      如果請(qǐng)求順利走到了響應(yīng)攔截器這一步,說(shuō)明這個(gè)請(qǐng)求已經(jīng)結(jié)束了 pending 狀態(tài),那我們要把它從 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 對(duì)象的場(chǎng)景

      遇到網(wǎng)絡(luò)波動(dòng)或者超時(shí)等情況造成請(qǐng)求錯(cuò)誤時(shí),需要清空原來(lái)存儲(chǔ)的所有 pending 狀態(tài)的請(qǐng)求記錄,在上面演示的代碼已經(jīng)作了注釋說(shuō)明。

      此外,頁(yè)面切換時(shí)也需要清空之前緩存的 pendingRequests 對(duì)象,可以利用 Vue Router 的 beforeEach 鉤子:

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

      功能擴(kuò)展

      1.統(tǒng)一處理接口報(bào)錯(cuò)提示

      與后端約定好接口返回?cái)?shù)據(jù)的格式,對(duì)接口報(bào)錯(cuò)的情況,可以統(tǒng)一在響應(yīng)攔截器中添加 toast 給用戶提示,

      對(duì)于特殊的不需要報(bào)錯(cuò)的接口,可以設(shè)置一個(gè)參數(shù)存入 axios 攔截器的 config 參數(shù)中,過(guò)濾掉報(bào)錯(cuò)提示:

      // 接口返回 retcode 不為 0 時(shí)需要報(bào)錯(cuò),請(qǐng)求設(shè)置了 noError 為 true 則這個(gè)接口不報(bào)錯(cuò)  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.發(fā)送請(qǐng)求時(shí)給控件添加 loading 效果

      上面利用 axios interceptors 過(guò)濾重復(fù)請(qǐng)求時(shí),可以在控制臺(tái)拋出信息給開發(fā)者提示,在這個(gè)基礎(chǔ)上如果能給頁(yè)面上操作的控件添加 loading  效果就會(huì)對(duì)用戶更友好。

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

      // 給 loadingTarget 對(duì)應(yīng)的控件添加 loading 效果,儲(chǔ)存 loadingService 實(shí)例 addLoading(config) {   if (!document.querySelector(config.loadingTarget)) return;   config.loadingService = Loading.service({     target: config.loadingTarget,   }); }  // 調(diào)用 loadingService 實(shí)例的 close 方法關(guān)閉對(duì)應(yīng)元素的 loading 效果 closeLoading(config) {   config.loadingService && config.loadingService.close(); }

      與上面過(guò)濾報(bào)錯(cuò)方式類似,發(fā)請(qǐng)求的時(shí)候?qū)⒃氐?class name 或 id 存入 axios 攔截器的 config 參數(shù)中,

      在請(qǐng)求攔截器中調(diào)用 addLoading 方法, 響應(yīng)攔截器中調(diào)用 closeLoading 方法,就可以實(shí)現(xiàn)在請(qǐng)求 pending 過(guò)程中指定控件(如  button) loading,請(qǐng)求結(jié)束后控件自動(dòng)取消 loading 效果。

      支持多個(gè)攔截器組合使用

      簡(jiǎn)單看下 axios interceptors 部分實(shí)現(xiàn)源碼可以理解,它支持定義多個(gè) interceptors,所以只要我們定義的  interceptors 符合 Promise.then 鏈?zhǔn)秸{(diào)用的規(guī)范,還可以添加更多功能:

      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()); }

      總結(jié)

      并發(fā)問(wèn)題很常見,處理起來(lái)又相對(duì)繁瑣,前端解決并發(fā)沖突時(shí),可以利用 axios 攔截器統(tǒng)一處理重復(fù)請(qǐng)求,簡(jiǎn)化業(yè)務(wù)代碼。

      同時(shí) axios 攔截器支持更多應(yīng)用,本文提供了部分常用擴(kuò)展功能的實(shí)現(xiàn),感興趣的同學(xué)可以繼續(xù)挖掘補(bǔ)充攔截器的其他用法。

      感謝各位的閱讀,以上就是“使用Axios攔截器解決前端并發(fā)沖突”的內(nèi)容了,經(jīng)過(guò)本文的學(xué)習(xí)后,相信大家對(duì)使用Axios攔截器解決前端并發(fā)沖突這一問(wèn)題有了更深刻的體會(huì),具體使用情況還需要大家實(shí)踐驗(yàn)證。這里是創(chuàng)新互聯(lián),小編將為大家推送更多相關(guān)知識(shí)點(diǎn)的文章,歡迎關(guān)注!


      網(wǎng)站名稱:使用Axios攔截器解決前端并發(fā)沖突
      分享網(wǎng)址:http://www.ef60e0e.cn/article/ggdpdj.html
      99热在线精品一区二区三区_国产伦精品一区二区三区女破破_亚洲一区二区三区无码_精品国产欧美日韩另类一区
      1. <ul id="0c1fb"></ul>

        <noscript id="0c1fb"><video id="0c1fb"></video></noscript>
        <noscript id="0c1fb"><listing id="0c1fb"><thead id="0c1fb"></thead></listing></noscript>

        保康县| 宁波市| 定安县| 临夏县| 游戏| 东山县| 湘潭市| 贞丰县| 油尖旺区| 横峰县| 稻城县| 札达县| 平原县| 芜湖县| 彭阳县| 高要市| 聊城市| 阜阳市| 秦安县| 墨脱县| 满城县| 滕州市| 安康市| 黑龙江省| 五峰| 当涂县| 外汇| 土默特左旗| 南充市| 新建县| 莒南县| 招远市| 宜川县| 合作市| 静安区| 陇川县| 叶城县| 扶绥县| 灵川县| 南部县| 徐闻县|