axios取消重复请求,cancelToken详解

446 阅读1分钟

1.为什么需要前端取消请求

  • 场景1: 同一个位置的展示,A,B两个地方可以触发该请求,点击A后,接口pengding,此时点击了B,这个两个请求的返回时间是不定的,也就是说页面上可能先展示A的结果,过段时间B请求返回了又变成了B的结果,也可能顺序相反
  • 场景2: 未管控重复点击,重复点击按钮查询
  • 场景3:后端接口返回太慢,导致用户点击几次,后面返回时间不定,出现重复查询

2.取消请求的方案

let cancel
const CancelToken = axios.CancelToken
axios.post('/result', {}, res => {
    resolve(res)
}, null, {
    headers: {
      'Content-Type': 'application/json;charset=UTF-8'
    },
    emulateJSON: false,
    cancelToken: CancelToken && new CancelToken(function executor (c) {
      // executor 函数接收一个 cancel 函数作为参数
      cancel = c
    })
    }).catch(e => {
        // 如果是cancel的,不进行错误处理
        if (e.$error && axios.isCancel(e.$error)) {
          return
        }
        reject(e)
    })
   
// 取消请求
cancel && cancel()

image.png

3.上述取消方案存在的问题

  • 场景1: 多个tab页,每个页面都会有相同的运行按钮,点击调用相同接口,如果用之前的方案,在tabB运行时,会取消掉tabA的运行,但需求是希望在当前tab只取消当前tab的请求,其他tab页的请求继续执行

4.改进方案

需要把每个请求给定唯一requestId,这样就可以定制化取消掉对应的请求。

此方案已经有个成熟的插件axios-cancel-plugin

使用:

import axios from 'axios';
import axiosCancel from 'axios-cancel-plugin';

axiosCancel(axios, {
  debug: false // default
});

axios.post('/result', {}, {
  requestId: requestId
}).then(() => {
    console.log('resolved post');
  }).catch(thrown => {
    if (axios.isCancel(thrown)) {
      console.log('request cancelled post');
    } else {
      console.log('some other reason post');
    }
  });
  
axios.cancel(requestId); // 即可取消对应requestId的请求,当然也可传数组,一次取消多个请求