axios之CancelToken取消请求

v0.22.0 开始,Axios 支持以 fetch API 方式------ AbortController 取消请求

此 API 从 v0.22.0 开始已被弃用,不应在新项目中使用

官网链接

1. 背景

最近项目中遇到一个场景,当连续触发一个请求时,如果是同一个接口,则保留最后一次的请求,之前的请求取消。

查阅了下axios文档,有一个属性CancelToken,把这个添加到axios配置中

2. 使用

1:在request时,添加cancelToken

javascript 复制代码
  request: [
    (config: AxiosRequestConfig) => {
      const cacheKey = `${config.method}${config.url}`
     
      if (config.autoCancel) {
        removeCache(cacheKey)
      }
      config.cancelToken = new axios.CancelToken((c) => {
        caches[cacheKey] = c
      })
      return config
    },
    (error: any) => Promise.reject(error),
  ],

2:在reponse时,删除key

javascript 复制代码
  response: [
    (res: AxiosResponse) => {
      const cacheKey = `${res.config.method}${res.config.url}`
      if (res.config.autoCancel) {
        removeCache(cacheKey)
      }
      return res
    },
    (error: any) => Promise.reject(error),
  ],

3:判断是否存在重复请求

javascript 复制代码
const caches: Record<string, Canceler> = {}
function removeCache(key: string) {
  if (caches[key]) {
    
    caches[key]()
    delete caches[key]
  }
}

这里的autoCancel 是为了解决url相同,请求参数不同时,自定义添加的,具体请求方式可以根据这个值来决定是否开启cancelToken

3. 全部代码

javascript 复制代码
/**
 * 通过取消重复请求解决请求"竞态"问题
 * - 如何定义"重复":method和url相同
 */
import axios, { AxiosRequestConfig, Canceler, AxiosResponse } from 'axios'

const caches: Record<string, Canceler> = {}
function removeCache(key: string) {
  if (caches[key]) {
    caches[key]()
    delete caches[key]
  }
}

const cancelInterceptors = {
  request: [
    (config: AxiosRequestConfig) => {
      const cacheKey = `${config.method}${config.url}`
      if (config.autoCancel) {
        removeCache(cacheKey)
      }
      config.cancelToken = new axios.CancelToken((c) => {
        caches[cacheKey] = c
      })
      return config
    },
    (error: any) => Promise.reject(error),
  ],
  response: [
    (res: AxiosResponse) => {
      const cacheKey = `${res.config.method}${res.config.url}`
      if (res.config.autoCancel) {
        removeCache(cacheKey)
      }
      return res
    },
    (error: any) => Promise.reject(error),
  ],
}

export default cancelInterceptors

在封装的axios里面添加配置

javascript 复制代码
// 往request请求中添加配置
service.interceptors.request.use(...cancelInterceptors.request)

// 往response请求中添加配置
service.interceptors.response.use(...cancelInterceptors.response)

在response失败error中axios返回了一个失败状态axios.isCancel(error)

javascript 复制代码
(error: AxiosError) => {
    // if (axios.isCancel(error) && error.message === SCRM_CANCEL_MESSAGE) {
    //   // 被手动取消的数据统计接口,不展示提示
    if (axios.isCancel(error)) {
      // 被取消的接口,不展示提示
    } else {
      message.error(error.response?.statusText || error.message || '网络错误')
    }

    // 网络层面错误,如接口地址写错了会走到这里
    return Promise.reject(error)
  }

3. 原理

source file:axios/lib/adapters/xhr.js

1:创建请求

javascript 复制代码
var request = new XMLHttpRequest()

if (config.cancelToken) {
  // Handle cancellation
  config.cancelToken.promise.then(function onCanceled(cancel) {
    if (!request) {
      return;
    }

    request.abort();
    reject(cancel);
    // Clean up request
    request = null;
  });
}

2:创建新的取消

在source file:axios/lib/cancel/CancelToken.js

javascript 复制代码
  var token = this;
  executor(function cancel(message) {
    if (token.reason) {
      // Cancellation has already been requested
      return;
    }

    token.reason = new Cancel(message);
    resolvePromise(token.reason);
  });
}

2:取消请求

在axios/lib/adapters/xhr.js文件中取消**request.abort();**请求,

javascript 复制代码
if (config.cancelToken) {

  // Handle cancellation

  config.cancelToken.promise.then(function onCanceled(cancel) {

    if (!request) {

      return;

    }



    request.abort();

    reject(cancel);

    // Clean up request

    request = null;

  });

}

笔记

相关推荐
MessiGo12 分钟前
Javascript 编程基础(5)面向对象 | 5.1、构造函数实例化对象
开发语言·javascript·原型模式
前端小白从0开始27 分钟前
Vue3项目实现WPS文件预览和内容回填功能
前端·javascript·vue.js·html5·wps·文档回填·文档在线预览
JohnYan1 小时前
Bun技术评估 - 03 HTTP Server
javascript·后端·bun
开开心心就好1 小时前
高效Excel合并拆分软件
开发语言·javascript·c#·ocr·排序算法·excel·最小二乘法
難釋懷1 小时前
Vue解决开发环境 Ajax 跨域问题
前端·vue.js·ajax
特立独行的猫a1 小时前
Nuxt.js 中的路由配置详解
开发语言·前端·javascript·路由·nuxt·nuxtjs
中微子1 小时前
小白也能懂:JavaScript 原型链和隐藏类的奇妙世界
javascript
咸虾米1 小时前
在uniCloud云对象中定义dbJQL的便捷方法
前端·javascript
梨子同志1 小时前
JavaScript Proxy 和 Reflect
前端·javascript
海的诗篇_1 小时前
移除元素-JavaScript【算法学习day.04】
javascript·学习·算法