axios 是如何实现取消请求的?

axios 是现在前端项目中最常使用的一个请求库,目前 Github star 已经达到了 104k star。

最近一段时间在看 axios 仓库源码,于是起了一个写"axios 源码系列"的念头,本文是这个系列的第一篇

源码系列的安排

我对这个源码系列的安排,不是循规蹈矩的从头说起,而是在阅读源码的过程当中,突然想写哪块内容我就写哪块。

不过,在座或在站的读者不用担心阅读的连贯性。这个系列的每篇文章内容相对独立,这样方便大家按需阅读。另外,每篇文章也会写得比较简短,保证大家在 5 分钟内看完,同时又能有所收获。

好了,书归正传。

本文我们讨论的问题是------axios 是如何实现取消请求(Cancel requests)的?

在 axios 中取消请求

axios 是这样取消请求的。

js 复制代码
const controller = new AbortController();

axios.get('https://httpstat.us/200', {
  signal: controller.signal
}).catch(error => {
  // 2) 在 catch 中捕获错误
  console.log(error) // { message: 'canceled', name: 'CanceledError', code: 'ERR_CANCELED' }
});
// 1) 取消请求
controller.abort()

AbortController 是在 DOM 标准中定义的 API,统一了取消类操作的实现,在浏览器端已经受到广泛支持了。

取消请求的实现

取消请求的实现位于 lib/adapters/xhr.js(暂不考虑 Node.js 实现)。

js 复制代码
// /v1.6.8/lib/adapters/xhr.js#L244
if (config.signal) {
  config.signal.aborted
    ? onCanceled() :
    config.signal.addEventListener('abort', onCanceled)
}

内部会判断是否传入了 signal 配置项。如果传入了,就监听 controller.signal 上的 abort 事件,这个事件会在调用 controller.abort() 方法时触发。

不过,还有一种可能是传入 controller.signal 时,先前就已经调用了 controller.abort(),这样 abort 事件永远都不会触发了。

不过没有关系,调用了 controller.abort() 后,controller.signal.aborted 属性会置为 true,因此可以通过 aborted 属性,确保 onCanceled 回调函数始终被调用。

onCanceled 处理函数内容如下。

js 复制代码
// /v1.6.8/lib/adapters/xhr.js#L234
onCanceled = cancel => {
  reject(!cancel || cancel.type
    ? new CanceledError(null, config, request) 
    : cancel
  );
  request.abort();
};

调用 controller.abort() 后,处理函数 onCanceled 会接受一个 cancel Event 参数,结构类似 { type: 'abort' } 这样,然后就会返回 axios 自定义的 CanceledError 错误。

这里有 2 个知识点:

  1. axios 对接口请求过程使用 new Promise((resolve,reject)){...} 进行了封装,确保始终返回 Promise 对象,这里的 reject(...) 表示"请求以失败告终"
  2. 至于 reject(cancel) 的分支逻辑,是为了兼容 CancelToken 的写法,这是旧的取消请求的实现,不过现在已经弃用了,新项目中不要再用了

最后,调用 request.abort(),这是实际终止当前请求的地方。

request 就是 XMLHttpRequest 实例,abort() 是 XMLHttpRequest 天然支持的用于终止请求的方法。

js 复制代码
// /v1.6.8/lib/adapters/xhr.js#L76
let request = new XMLHttpRequest();

到此,我们就完成了 axios 取消请求的实现介绍。你是否看懂了呢?

总结

取消请求是 axios 提供的核心功能之一,本文我们介绍了它在浏览器端的实现。

axios 在浏览器端是使用 XMLHttpRequest API 提供请求能力的,其实例上提供了 abort() 方法用于终止请求,而 axios 就是利用这一点跟 AbortController API 配合实现请求的取消的。

相关推荐
云运维笔记4 小时前
华为VRP系统文件管理全攻略
前端·华为
走到天涯海角4 小时前
pinia和Vuex的区别以及使用pinia
开发语言·前端·javascript
电梯界知识分子5 小时前
江西抚州临川九尊府五层别墅:受限楼梯间里,全黑铝合金观光井道配曳引龙门架的落地记录
大数据·前端·网络·算法·家用电梯
晴天165 小时前
Web 页面内存溢出与 CPU 溢出:区别、诊断与最佳实践
前端·javascript
摸鱼仙人~5 小时前
需求深度分析提示词-grill me
前端·chrome
Highcharts.js5 小时前
常见报错排雷指南3:兼容性问题的官方解法
前端·javascript·react.js·可视化·highcharts·报错解法
雪芽蓝域zzs5 小时前
第三十六节:keep-alive 页面缓存(Vue3 + 后台管理系统)
前端·vue.js·缓存
言乐65 小时前
Python加速器2视频网页加速器
前端·javascript·css·python·音视频
IT_陈寒6 小时前
为什么我的Java Stream操作总是默默吃掉异常?
前端·人工智能·后端
志尊宝6 小时前
Vue3 零基础每日笔记(017):事件处理进阶——$event、多事件与事件修饰符全家桶
javascript·vue.js·笔记