axios全局封装AbortController取消重复请求

为什么?

问题:为什么axios要配置AbortController?防抖节流不行吗?

分析:

  • 防抖节流本质上是用延时器来操作请求的。
  • 防抖是判断延时器是否存在,如果存在,清除延时器,重新开启一个延时器,只执行最后一次请求。
  • 节流呢,是判断延时器是否存在,如果存在,直接return掉,直到执行完这个延时器。
  • 事实上,这些体验感都不算友好,因为对于用户来说,得等一些时间,尤其是首次请求,不是那么流畅。
  • 而当我们配置了AbortController,就可以中断掉重复的请求,并且首次不需要等待时间,是非常友好的行为。
  • 从axios0.22.0开始,开始支持AbortController,并且废弃CancelToken。之所以我们不用CancelToken来取消请求,是因为CancelToken存在内存泄漏隐患,并不安全,所以官方人员希望用户们升级版本,使用AbortController减少内存泄漏风险。
  • 事实上,凡事用xhr封装的请求库,都可以配置AbortController,如fetch,axios,alova等等
  • 本文封装的原理可以移步至另一篇博客查看:如何避免接口重复请求(axios推荐使用AbortController)-CSDN博客

前置条件:

升级axios至最新版本。因为AbortController是从0.22.0开始支持的。如果你的版本已经在0.22.0以上,可以正常使用,不升级亦可。

以笔者升级的项目为例,我这里的版本是很古老的0.18.0,所以我这里是直接把axios升级至目前最新的稳定版本1.7.2。(如果升级失败,可以先移除掉axios,再重新安装。)

javascript 复制代码
//安装axios
npm i axios
//卸载axios
npm uninstall axios

接入步骤:

1.在封装axios的全局文件中,先定义两个变量

复制代码
在全局封装axios的request.js文件的全局里定义两个变量
isCancel 用来判断请求是否被取消
cacheRequest 用来存储需要取消重复请求的接口
javascript 复制代码
// isCancel-取消标识 可以根据这个值判断请求是否被取消
const { isCancel } = axios
const cacheRequest = {}

2.定义一个函数,用来取消请求和删除cacheRequest里对应的请求

javascript 复制代码
// 删除缓存队列中的请求
function abortCacheRequest(reqKey) {
  if (cacheRequest[reqKey]) {
    // 通过AbortController实例上的abort来终止请求
    cacheRequest[reqKey].abort()
    delete cacheRequest[reqKey]
  }
}

3.在请求拦截器里加入取消重复请求的逻辑

之所以做成根据isAbort标识判断是否使用AbortController,是因为并不是所有的请求都是需要取消重复请求的,就像并不是所有的请求都需要防抖节流一样,所以当我们有需要的时候,再加这个标识就好。

javascript 复制代码
const service = axios.create({
  baseURL: hosts.server, // api 的 base_url
  timeout: 50e3, // request timeout
});

service.interceptors.request.use(config => {
    // isAbort - 是config里配置的是否清除相同请求的标识,不传则默认是不需要清除
    const { url, method, isAbort= false } = config
    if (isAbort) {
        // 请求地址和请求方式组成唯一标识,将这个标识作为取消函数的key,保存到请求队列中
        const reqKey = `${url}&${method}`
        // 如果config传了需要清除重复请求的isAbort,则如果存在重复请求,删除之前的请求
        abortCacheRequest(reqKey)
        // 将请求加入请求队列,通过AbortController来进行手动取消
        const controller = new AbortController()
        config.signal = controller.signal
        cacheRequest[reqKey] = controller
    }
})

4.在响应拦截器里加入判断

如果请求成功后,清除cacheRequest里对应的存储;并且在error里判断,取消的请求不做任何处理

javascript 复制代码
service.interceptors.response.use(res => {
  // 请求成功,从队列中移除
  const { url, method, isAbort = false } = response.config
  if (isAbort) delete cacheRequest[`${url}&${method}`]
}), error => {
  if (isCancel(error)) {
    // 通过AbortController取消的请求不做任何处理
    return Promise.reject({
      message: '重复请求,已取消'
    })
  }
}

5.使用

在调用接口的时候,增加一个isAbort的标识为true就能开启取消重复请求的功能了

javascript 复制代码
//请求示例
export function getList(data) {
  return request({
    url: '/list',
    method: 'post',
    data: data,
    isAbort: true // 配置标识 如果该接口频繁请求 则会中断上次请求保留最新一次请求
  })
}

效果图:

体验感极佳,status为canceled,都是被取消的请求

小拓展:

如何取消xhr的请求:

javascript 复制代码
xhr.abort()

如何取消fetch请求:

javascript 复制代码
let controller = new AbortController();
let signal = controller.signal;

fetch(url, {signal});

controller.abort(); // 取消请求

//监听请求取消情况
signal.addEventListener('abort',
  () => console.log('abort!',signal.aborted)
);
相关推荐
Apifox11 分钟前
如何在 Apifox 中通过 Runner 运行包含云端数据库连接配置的测试场景
前端·后端·ci/cd
-代号952716 分钟前
【JavaScript】十四、轮播图
javascript·css·css3
树上有只程序猿39 分钟前
后端思维之高并发处理方案
前端
庸俗今天不摸鱼1 小时前
【万字总结】前端全方位性能优化指南(十)——自适应优化系统、遗传算法调参、Service Worker智能降级方案
前端·性能优化·webassembly
QTX187301 小时前
JavaScript 中的原型链与继承
开发语言·javascript·原型模式
黄毛火烧雪下1 小时前
React Context API 用于在组件树中共享全局状态
前端·javascript·react.js
Apifox2 小时前
如何在 Apifox 中通过 CLI 运行包含云端数据库连接配置的测试场景
前端·后端·程序员
一张假钞2 小时前
Firefox默认在新标签页打开收藏栏链接
前端·firefox
高达可以过山车不行2 小时前
Firefox账号同步书签不一致(火狐浏览器书签同步不一致)
前端·firefox
m0_593758102 小时前
firefox 136.0.4版本离线安装MarkDown插件
前端·firefox