axios取消重復(fù)請求

在開發(fā)中,經(jīng)常會遇到接口重復(fù)請求導(dǎo)致的各種問題。

對于重復(fù)的get請求,會導(dǎo)致頁面更新多次,發(fā)生頁面抖動的現(xiàn)象,影響用戶體驗。

對于重復(fù)的post請求,會導(dǎo)致在服務(wù)端生成兩次記錄(例如生成兩條訂單記錄)。

如果當(dāng)前頁面請求還未響應(yīng)完成,就切換到了下一個路由,那么這些請求直到響應(yīng)返回才會中止。

無論從用戶體驗或者從業(yè)務(wù)嚴(yán)謹(jǐn)方面來說,取消無用的請求確實是需要避免的。

當(dāng)然我們可以通過頁面loading來避免用戶進行下一次的操作,但本文只討論單純的如何取消這些無用的請求。

axios 的 cancelToken

axios是一個主流的http請求庫,它提供了兩種取消請求的方式。

  • 通過axios.CancelToken.source生成取消令牌token和取消方法cancel
const CancelToken = axios.CancelToken;
const source = CancelToken.source();

axios.get('/user/12345', {
  cancelToken: source.token
}).catch(function(thrown) {
  if (axios.isCancel(thrown)) {
    console.log('Request canceled', thrown.message);
  } else {
    // handle error
  }
});

axios.post('/user/12345', {
  name: 'new name'
}, {
  cancelToken: source.token
})

// cancel the request (the message parameter is optional)
source.cancel('Operation canceled by the user.');
  • 通過axios.CancelToken構(gòu)造函數(shù)生成取消函數(shù)
const CancelToken = axios.CancelToken;
let cancel;

axios.get('/user/12345', {
  cancelToken: new CancelToken(function executor(c) {
    // An executor function receives a cancel function as a parameter
    cancel = c;
  })
});

// cancel the request
cancel();

需要注意的是在catch中捕獲異常時,應(yīng)該使用axios.isCancel()判斷當(dāng)前請求是否是主動取消的,以此來區(qū)分普通的異常邏輯。

封裝取消請求邏輯

上面有兩種取消請求,用哪種都是可以的,這里使用第二種。
取消請求主要有兩個場景:

  • 當(dāng)請求方式method,請求路徑url,請求參數(shù)(get為params,post為data)都相同時,可以視為同一個請求發(fā)送了多次,需要取消之前的請求
  • 當(dāng)路由切換時,需要取消上個路由中未完成的請求

封裝幾個方法:

// 聲明一個 Map 用于存儲每個請求的標(biāo)識 和 取消函數(shù)
const pending = new Map()
/**
 * 添加請求
 * @param {Object} config 
 */
const addPending = (config) => {
  const url = [
    config.method,
    config.url,
    JSON.stringify(config.params),
    JSON.stringify(config.data)
  ].join('&')
  config.cancelToken = config.cancelToken || new axios.CancelToken(cancel => {
    if (!pending.has(url)) { // 如果 pending 中不存在當(dāng)前請求,則添加進去
      pending.set(url, cancel)
    }
  })
}
/**
 * 移除請求
 * @param {Object} config 
 */
const removePending = (config) => {
  const url = [
    config.method,
    config.url,
    JSON.stringify(config.params),
    JSON.stringify(config.data)
  ].join('&')
  if (pending.has(url)) { // 如果在 pending 中存在當(dāng)前請求標(biāo)識,需要取消當(dāng)前請求,并且移除
    const cancel = pending.get(url)
    cancel(url)
    pending.delete(url)
  }
}
/**
 * 清空 pending 中的請求(在路由跳轉(zhuǎn)時調(diào)用)
 */
export const clearPending = () => {
  for (const [url, cancel] of pending) {
    cancel(url)
  }
  pending.clear()
}

MapES6中一種新型的數(shù)據(jù)結(jié)構(gòu),本身提供了諸多方法,方便操作,適合當(dāng)前場景。如果不熟悉的可以查看ECMAScript 6 入門。
在給config.cancelToken賦值的時候,需要判斷當(dāng)前請求是否已經(jīng)在業(yè)務(wù)代碼中使用了cancelToken
Map結(jié)構(gòu)默認(rèn)部署了Symbol.iterator屬性,可以使用for...of循環(huán)直接獲取鍵名和鍵值,當(dāng)然你也可以使用for...in循環(huán)。

在 axios 攔截器中使用

主要的方法已經(jīng)寫好了,只需要添加到axios攔截器中就可以了。

axios.interceptors.request.use(config => {
  removePending(options) // 在請求開始前,對之前的請求做檢查取消操作
  addPending(options) // 將當(dāng)前請求添加到 pending 中
  // other code before request
  return config
}, error => {
  return Promise.reject(error)
})

axios.interceptors.response.use(response => {
  removePending(response) // 在請求結(jié)束后,移除本次請求
  return response
}, error => {
  if (axios.isCancel(error)) {
    console.log('repeated request: ' + error.message)
  } else {
    // handle error code
  }
  return Promise.reject(error)
})
clearPending()方法添加到vue路由鉤子函數(shù)中
router.beforeEach((to, from, next) => {
  clearPending()
  // ...
  next()
})
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 項目地址:https://github.com/Ewall1106/mall[https://github.com...
    ComfyUI閱讀 886評論 0 1
  • 最近做項目遇到一個需求,需要在切換路由時,取消當(dāng)前所有未完成的請求,隱約記得axios中有cancelToken這...
    sunshineLWZL閱讀 14,442評論 12 17
  • 由于接口響應(yīng)速度等原因,在項目開發(fā)中經(jīng)常需要處理重復(fù)點擊導(dǎo)致多次調(diào)用接口的問題,針對每個接口調(diào)用單獨處理相對繁瑣,...
    LongfeiSong閱讀 2,259評論 0 1
  • 自己碰到的問題,扒了很多文檔才理清楚,當(dāng)做是筆記記下來說到取消接口請求,可能沒碰到這樣的坑冷不丁還有點懵,為什么會...
    蝸牛先笙閱讀 77,167評論 33 126
  • 久違的晴天,家長會。 家長大會開好到教室時,離放學(xué)已經(jīng)沒多少時間了。班主任說已經(jīng)安排了三個家長分享經(jīng)驗。 放學(xué)鈴聲...
    飄雪兒5閱讀 7,810評論 16 22

友情鏈接更多精彩內(nèi)容