淺談axios中取消請求及阻止重復請求的方法
前言
在實際項目中,我們可能需要對請求進行“防抖”處理。這裡主要是為瞭阻止用戶在某些情況下短時間內重復點擊某個按鈕,導致前端向後端重復發送多次請求。這裡我列舉兩種比較常見的實際情況:
- PC端 – 用戶雙擊搜索按鈕,可能會觸發兩次搜索請求
- 移動端 – 因移動端沒有點擊延遲,所以極易造成誤操作或多操作,造成請求重發
以上情況有可能在有Loading遮罩時依然發生,所以我們要考慮前端阻止重復請求的方法。
核心——CancelToken
在Axios中取消請求最核心的方法是CanelToken。在官網文檔中有寫到兩種方法使用CancelToken,這裡簡單粘貼出來,並增加瞭註釋
方法1:
const CancelToken = axios.CancelToken; const source = CancelToken.source(); axios.get('/user/12345', { // 必須對請求進行cancelToken設置 cancelToken: source.token }).catch(function (thrown) { // 如果請求被取消則進入該方法判斷 if (axios.isCancel(thrown)) { console.log('Request canceled', thrown.message); } else { // handle error } }); // 取消上面的請求 // source.cancel('messge') message為可選項,必須為String source.cancel('Operation canceled by the user.');
方法2:
const CancelToken = axios.CancelToken; let cancel; axios.get('/user/12345', { // 在options中直接創建一個cancelToken對象 cancelToken: new CancelToken(function executor(c) { cancel = c; }) }); // 取消上面的請求 cancel();
實際應用和封裝
上文已對axios中的核心方法進行瞭舉例,但是在實際中我們往往不會像官網例子中那樣使用,更多的是在axios的攔截器中做全局配置管理。這樣的話我們需要對上面的代碼進行一些改變。
這裡說一下我實現的大體思路:
- 我們需要對所有正在進行中的請求進行緩存。在請求發起前判斷緩存列表中該請求是否正在進行,如果有則取消本次請求。
- 在任意請求完成後,需要在緩存列表中刪除該次請求,以便可以重新發送該請求
思路說完,我們直接上代碼
// 正在進行中的請求列表 let reqList = [] /** * 阻止重復請求 * @param {array} reqList - 請求緩存列表 * @param {string} url - 當前請求地址 * @param {function} cancel - 請求中斷函數 * @param {string} errorMessage - 請求中斷時需要顯示的錯誤信息 */ 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) } /** * 允許某個請求可以繼續進行 * @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 // 設置cancelToken對象 config.cancelToken = new axios.CancelToken(function(c) { cancel = c }) // 阻止重復請求。當上個請求未完成時,相同的請求不會進行 stopRepeatRequest(reqList, config.url, cancel, `${config.url} 請求被中斷`) return config }, err => Promise.reject(err) ) // 響應攔截器 service.interceptors.response.use( response => { // 增加延遲,相同請求不得在短時間內重復發送 setTimeout(() => { allowRequest(reqList, response.config.url) }, 1000) // ...請求成功後的後續操作 // successHandler(response) }, error => { if (axios.isCancel(thrown)) { console.log(thrown.message); } else { // 增加延遲,相同請求不得在短時間內重復發送 setTimeout(() => { allowRequest(reqList, error.config.url) }, 1000) } // ...請求失敗後的後續操作 // errorHandler(error) } )
一些小細節
為什麼沒用前文方法2中的代碼進行cancelToken設置?
axios的文檔中有一條備註:
Note: you can cancel several requests with the same cancel token.
你可以使用相同的Token來取消多個請求
所以我不想在每個請求前都new一個新的對象
請務必使用方法2,保證每次cancel都能正確執行。之前方法會導致當出現cancel後,後續請求也會持續cancel
為什麼在response中需要增加延遲?
因為不想讓用戶在極短的時間內重復進行相同請求。
請註意,在response中阻止請求和在request中的阻止請求是兩個概念:
request中是阻止上個請求 未完成 時又開始瞭相同的請求
response中是阻止上個請求 完成後 一段時間內不允許相同請求
我能否在cancel時傳遞一個對象,而不僅僅是message?
以官方提供的接口來看是不可以的,你可以仿照官方源碼進行重新封裝,或者使用第三方插件,或者使用另一個方法:將對象轉換為JSON字符串,然後在需要的地方再轉換回來
到此這篇關於淺談axios中取消請求及阻止重復請求的方法的文章就介紹到這瞭,更多相關axios中取消請求及阻止重復請求內容請搜索WalkonNet以前的文章或繼續瀏覽下面的相關文章希望大傢以後多多支持WalkonNet!
推薦閱讀:
- 項目中如何使用axios過濾多次重復請求詳解
- js實現axios限制請求隊列
- JavaScript 中斷請求幾種方案詳解
- 一文掌握ajax、fetch和axios的區別對比
- 淺談Axios去除重復請求方案