您好,登錄后才能下訂單哦!
這篇文章主要介紹了axios中如何實(shí)現(xiàn)取消請求及阻止重復(fù)請求,具有一定借鑒價(jià)值,感興趣的朋友可以參考下,希望大家閱讀完這篇文章之后大有收獲,下面讓小編帶著大家一起了解一下。
在實(shí)際項(xiàng)目中,我們可能需要對請求進(jìn)行“防抖”處理。這里主要是為了阻止用戶在某些情況下短時(shí)間內(nèi)重復(fù)點(diǎn)擊某個(gè)按鈕,導(dǎo)致前端向后端重復(fù)發(fā)送多次請求。這里我列舉兩種比較常見的實(shí)際情況:
PC端 - 用戶雙擊搜索按鈕,可能會(huì)觸發(fā)兩次搜索請求
移動(dòng)端 - 因移動(dòng)端沒有點(diǎn)擊延遲,所以極易造成誤操作或多操作,造成請求重發(fā)
以上情況有可能在有Loading遮罩時(shí)依然發(fā)生,所以我們要考慮前端阻止重復(fù)請求的方法。
在Axios中取消請求最核心的方法是CanelToken。在官網(wǎng)文檔中有寫到兩種方法使用CancelToken,這里簡單粘貼出來,并增加了注釋
方法1:
const CancelToken = axios.CancelToken; const source = CancelToken.source(); axios.get('/user/12345', { // 必須對請求進(jìn)行cancelToken設(shè)置 cancelToken: source.token }).catch(function (thrown) { // 如果請求被取消則進(jìn)入該方法判斷 if (axios.isCancel(thrown)) { console.log('Request canceled', thrown.message); } else { // handle error } }); // 取消上面的請求 // source.cancel('messge') message為可選項(xiàng),必須為String source.cancel('Operation canceled by the user.');
方法2:
const CancelToken = axios.CancelToken; let cancel; axios.get('/user/12345', { // 在options中直接創(chuàng)建一個(gè)cancelToken對象 cancelToken: new CancelToken(function executor(c) { cancel = c; }) }); // 取消上面的請求 cancel();
上文已對axios中的核心方法進(jìn)行了舉例,但是在實(shí)際中我們往往不會(huì)像官網(wǎng)例子中那樣使用,更多的是在axios的攔截器中做全局配置管理。這樣的話我們需要對上面的代碼進(jìn)行一些改變。
這里說一下我實(shí)現(xiàn)的大體思路:
我們需要對所有正在進(jìn)行中的請求進(jìn)行緩存。在請求發(fā)起前判斷緩存列表中該請求是否正在進(jìn)行,如果有則取消本次請求。
在任意請求完成后,需要在緩存列表中刪除該次請求,以便可以重新發(fā)送該請求
思路說完,我們直接上代碼
// 正在進(jìn)行中的請求列表 let reqList = [] /** * 阻止重復(fù)請求 * @param {array} reqList - 請求緩存列表 * @param {string} url - 當(dāng)前請求地址 * @param {function} cancel - 請求中斷函數(shù) * @param {string} errorMessage - 請求中斷時(shí)需要顯示的錯(cuò)誤信息 */ const stopRepeatRequest = function (reqList, url, cancel, errorMessage) { const errorMsg = errorMessage || '' for (let i = 0; i < reqList.length; i++) { if (reqList[i] === url) { cancel(errorMsg) return } } reqList.push(url) } /** * 允許某個(gè)請求可以繼續(xù)進(jìn)行 * @param {array} reqList 全部請求列表 * @param {string} url 請求地址 */ const allowRequest = function (reqList, url) { for (let i = 0; i < reqList.length; i++) { if (reqList[i] === url) { reqList.splice(i, 1) break } } } const service = axios.create() // 請求攔截器 service.interceptors.request.use( config => { let cancel // 設(shè)置cancelToken對象 config.cancelToken = new axios.CancelToken(function(c) { cancel = c }) // 阻止重復(fù)請求。當(dāng)上個(gè)請求未完成時(shí),相同的請求不會(huì)進(jìn)行 stopRepeatRequest(reqList, config.url, cancel, `${config.url} 請求被中斷`) return config }, err => Promise.reject(err) ) // 響應(yīng)攔截器 service.interceptors.response.use( response => { // 增加延遲,相同請求不得在短時(shí)間內(nèi)重復(fù)發(fā)送 setTimeout(() => { allowRequest(reqList, response.config.url) }, 1000) // ...請求成功后的后續(xù)操作 // successHandler(response) }, error => { if (axios.isCancel(thrown)) { console.log(thrown.message); } else { // 增加延遲,相同請求不得在短時(shí)間內(nèi)重復(fù)發(fā)送 setTimeout(() => { allowRequest(reqList, error.config.url) }, 1000) } // ...請求失敗后的后續(xù)操作 // errorHandler(error) } )
為什么沒用前文方法2中的代碼進(jìn)行cancelToken設(shè)置?
axios的文檔中有一條備注:
Note: you can cancel several requests with the same cancel token.
你可以使用相同的Token來取消多個(gè)請求
所以我不想在每個(gè)請求前都new一個(gè)新的對象
請務(wù)必使用方法2,保證每次cancel都能正確執(zhí)行。之前方法會(huì)導(dǎo)致當(dāng)出現(xiàn)cancel后,后續(xù)請求也會(huì)持續(xù)cancel
為什么在response中需要增加延遲?
因?yàn)椴幌胱層脩粼跇O短的時(shí)間內(nèi)重復(fù)進(jìn)行相同請求。
請注意,在response中阻止請求和在request中的阻止請求是兩個(gè)概念:
request中是阻止上個(gè)請求 未完成 時(shí)又開始了相同的請求
response中是阻止上個(gè)請求 完成后 一段時(shí)間內(nèi)不允許相同請求
我能否在cancel時(shí)傳遞一個(gè)對象,而不僅僅是message?
以官方提供的接口來看是不可以的,你可以仿照官方源碼進(jìn)行重新封裝,或者使用第三方插件,或者使用另一個(gè)方法:將對象轉(zhuǎn)換為JSON字符串,然后在需要的地方再轉(zhuǎn)換回來
感謝你能夠認(rèn)真閱讀完這篇文章,希望小編分享的“axios中如何實(shí)現(xiàn)取消請求及阻止重復(fù)請求”這篇文章對大家有幫助,同時(shí)也希望大家多多支持億速云,關(guān)注億速云行業(yè)資訊頻道,更多相關(guān)知識(shí)等著你來學(xué)習(xí)!
免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。