項目中如何使用axios過濾多次重復請求詳解
一、前言:
我們在web應用開發過程當中,經常會遇到一個時刻發起瞭多個請求的場景
這個情況下,我們通常的做法有兩種:
- 可以在請求時show一個loading,阻止用戶操作。
- 或者人為加個變量,做一個請求的節流
我們的項目中,目前大部分情況也是采用以上兩種方式做的。今天來介紹一個新的方式。
二、CancelToken類
我們之前實例化一個Promise,這個對象是否成功與否,是無法在函數外部決定的,這裡邊使用要用到一個小竅門,可以讓一個promise 和resolve分離。任何時機都可以觸發resolve:
// 一個promise let resolvePromise let p = new Promise((resolve, reject) => { resolvePromise = resolve }) // 這樣在外部執行 resolvePromise()
ok,有瞭這個前提,我們需要借助axios.CancelToken這個類。
這個類相當於在每次請求的時候開啟另一個promise和當前的請求形成一個promise.race(請求p1,取消請求p2),在promise中的resolve方法賦值給瞭一個外部的變量去接收。我們可以根據需求,人為決定是否取消前次請求。其實這就類似,原來我們寫fetch封裝接口超時的Promise.race類似。
cancelToken中也提供瞭相應的static方法source用來生成一個cancelToken和一個cancel方法其實就是這個promise的一個resolve。
CancelToken.source = function source() { var cancel; // var token = new CancelToken(function executor(c) { cancel = c; }); return { token: token, cancel: cancel, };
根據我們常用的的緩存方式,我們可以聲明一個map來存儲每次請求的url,同時存儲對應的cancel方法。
// 聲明一個全局map const pendingHttp = new Map() // axios中內置的CancelToken類 const CancelToken = axios.CancelToken function addApi (config) { config.cancelToken = new CancelToken((cancel) => { const url = config.url console.log(pendingHttp) if (!pendingHttp.has(url)) { pendingHttp.set(url, cancel) } }) } function cancelApi (config) { const url = config.url if (pendingHttp.has(url)) { // 如果在 pending 中存在當前請求標識,需要取消當前請求,並且移除 const cancel = pendingHttp.get(url) cancel(url + '取消瞭') pendingHttp.delete(url) // 清空當前url的緩存 } }
- 要特殊註意,要想取消掉一個請求,需要在config上添加cancelToken這個屬性賦值為CancelToken的實例。否則cancel不掉。
就像操作定時器一樣,要先嘗試取消上一次,然後再開啟下一次
httpService.interceptors.request.use(config => { cancelApi(config) addApi(config) // 本地調試的時候,是跨域的情況,加請求頭會有限制(此處是項目代碼無關緊要) const { headers = {} } = config; const { globalObj = {} } = window Object.assign(headers, globalObj, { from }) return config }, error => { console.log(error) return Promise.reject(error) })
然後還有一種可能性,第一次請求已經返回瞭,又發起瞭相同的一次請求,所以在response裡邊也要cancelApi一下。
httpService.interceptors.response.use( response => { cancelApi(response.config) sentryCatchApi(response) }, error => { // 請求超時 if (error.message.includes('timeout')) { // 判斷請求異常信息中是否含有超時timeout字符串 Toast.error({ text: '網頁請求超時,請刷新重試~' }) } sentryCatchApi(error) return Promise.reject(error) } )
我們需要註意一點,cancel其實就是resolve,我們cancel執行時候傳入的參數,會最終在response的error回調中,作為參數返回,這樣我們的捕捉錯誤的方法可能會有報錯。
// 假設我們的error方法是這樣封裝的。 來看一下sentryCatchApi error => { sentryCatchApi(error) return Promise.reject(error) } // 由於這個方法需要接收一個對象,但是我們cancel取消請求的情況下,返回的是一個字符串,這時就報錯瞭。 function sentryCatchApi (res) { try { res = res || {} const resData = res.data || {} Sentry.captureException(JSON.stringify(resData)) console.log(` 獲取數據失敗: 請在瀏覽器中打開進入 webview的地址,並粘貼出來,便於問題排查 :接口相關信息: 接口地址:${res.config.url}, 接口返回值:code:${resData.code}, message:${resData.message}, data:${JSON.stringify(resData.data)} `) } catch (err) { console.error(err) } }
需要使用isCancel這個api
error => { if (axios.isCancel(error)) return console.log('請求被取消瞭', error.message) sentryCatchApi(error) return Promise.reject(error) }
最終效果
控制臺也沒有任何報錯啦。(後續完善到項目中)
總結
到此這篇關於項目中如何使用axios過濾多次重復請求的文章就介紹到這瞭,更多相關axios過濾多次重復請求內容請搜索WalkonNet以前的文章或繼續瀏覽下面的相關文章希望大傢以後多多支持WalkonNet!