Axios源码笔记 | 深度剖析 Cancel 取消请求体系,从源码到设计思路

举报
叶一一 发表于 2025/06/24 09:19:20 2025/06/24
【摘要】 一、引言在前端开发的日常工作中,HTTP 请求是与后端进行数据交互的重要手段。然而,在一些复杂的业务场景下,比如用户频繁操作页面,可能会触发多个不必要的请求;或者在页面跳转时,之前发起的请求如果还未完成,就需要及时取消,以避免资源浪费和不必要的错误。Axios 作为一款广泛使用的 HTTP 客户端库,提供了强大的请求取消功能,这一功能主要集中在 axios-1.x/lib/cancel 目录...

一、引言

在前端开发的日常工作中,HTTP 请求是与后端进行数据交互的重要手段。然而,在一些复杂的业务场景下,比如用户频繁操作页面,可能会触发多个不必要的请求;或者在页面跳转时,之前发起的请求如果还未完成,就需要及时取消,以避免资源浪费和不必要的错误。Axios 作为一款广泛使用的 HTTP 客户端库,提供了强大的请求取消功能,这一功能主要集中在 axios-1.x/lib/cancel 目录下。

接下来,我们将深入剖析该目录下的 CanceledError.jsCancelToken.jsisCancel.js 这三个文件,揭开 Axios 取消请求体系的神秘面纱。

二、CanceledError.js 源码解析

2.1 核心代码

'use strict';

var utils = require('../utils');

function CanceledError(message, config, request) {
  Error.call(this);
  this.message = message;
  this.name = 'CanceledError';
  this.config = config;
  this.request = request;
  if (Error.captureStackTrace) {
    Error.captureStackTrace(this, CanceledError);
  }
}

// 继承 Error 类
utils.inherits(CanceledError, Error);

module.exports = CanceledError;

这段代码定义了一个 CanceledError 类,用于表示请求被取消时抛出的错误。在构造函数中,首先调用 Error.call(this) 来继承 Error 类的基本属性,然后设置了自定义的属性 messagenameconfig request,分别用于存储错误信息、错误名称、请求配置和请求对象。Error.captureStackTrace 方法用于捕获错误堆栈信息,方便调试。最后,通过 utils.inherits 方法让 CanceledError 类正式继承 Error 类。

2.2 设计思路

在请求取消的场景下,需要有一个特定的错误类型来标识这种情况,以便开发者在代码中进行针对性的错误处理。通过创建 CanceledError 类,将请求取消相关的错误信息进行统一封装,并且保留了原始的请求配置和请求对象,有助于开发者更好地定位和解决问题。

2.3 重点逻辑

  • 错误继承:通过 utils.inherits 方法实现 CanceledError 类对 Error 类的继承,确保它是一个标准的错误对象,能够被 try...catch 语句捕获。
  • 堆栈信息捕获:使用 Error.captureStackTrace 方法捕获错误堆栈信息,方便开发者在调试时快速定位问题。

三、CancelToken.js 源码解析

3.1 核心代码

'use strict';

var Cancel = require('./Cancel');

function CancelToken(executor) {
  if (typeof executor !== 'function') {
    throw new TypeError('executor must be a function.');
  }

  var resolvePromise;
  this.promise = new Promise(function promiseExecutor(resolve) {
    resolvePromise = resolve;
  });

  var token = this;
  executor(function cancel(message) {
    if (token.reason) {
      // 已经取消,忽略
      return;
    }
    token.reason = new Cancel(message);
    resolvePromise(token.reason);
  });
}

CancelToken.source = function source() {
  var cancel;
  var token = new CancelToken(function executor(c) {
    cancel = c;
  });
  return {
    token: token,
    cancel: cancel
  };
};

CancelToken.prototype.throwIfRequested = function throwIfRequested() {
  if (this.reason) {
    throw this.reason;
  }
};

module.exports = CancelToken;

CancelToken 类是 Axios 取消请求体系的核心。构造函数接收一个 executor 函数作为参数,该函数会接收一个 cancel 函数。在构造函数内部,创建了一个 Promise 对象,当调用 cancel 函数时,会将 Promise 的状态置为 resolved,并传递取消原因。CancelToken.source 是一个静态方法,用于便捷地创建 CancelToken 实例和对应的 cancel 函数。throwIfRequested 方法用于检查请求是否已经被取消,如果是则抛出取消原因。

3.2 设计思路

CancelToken 的设计目的是提供一种机制,让开发者可以在请求发送前或发送过程中取消请求。通过 Promise 来管理取消状态,使得取消操作可以与请求的生命周期进行交互。source 静态方法简化了 CancelToken 实例和 cancel 函数的创建过程,提高了开发效率。

3.3 重点逻辑

  • Promise 管理:利用 Promise 来跟踪取消状态,当调用 cancel 函数时,将 Promise 状态置为 resolved,通知请求取消。
  • source 方法:提供一种简洁的方式创建 CancelToken 实例和对应的 cancel 函数,方便开发者使用。
  • throwIfRequested 方法:在请求发送前或处理响应时检查请求是否已被取消,避免无效的请求处理。

四、isCancel.js 源码解析

4.1 核心代码

'use strict';

export default function isCancel(value) {
  return !!(value && value.__CANCEL__);
}

这段代码定义了一个名为 isCancel 的函数,用于判断一个值是否是由 Cancel 类创建的取消对象。通过双重取反操作,将结果转换为布尔值返回。

4.2 设计思路

在处理请求取消的错误时,开发者可能需要判断错误是否是由于请求取消引起的。isCancel 函数提供了一种简单而高效的方式来进行判断,提高了代码的健壮性和可维护性。

4.3 重点逻辑

  • 属性检查:通过检查传入值是否存在且包含 __CANCEL__ 属性来判断是否为取消对象。
  • 布尔值转换:使用双重取反操作将结果转换为布尔值,确保返回值的类型一致。

五、结语

本文深入剖析了 Axios 1.x 版本中 axios-1.x/lib/cancel 目录下的三个核心文件。CanceledError.js 定义了请求取消时抛出的错误类型,为错误处理提供了统一的标准;CancelToken.js 作为取消请求体系的核心,通过 Promise 管理取消状态,提供了灵活的取消请求机制;isCancel.js 则提供了一个简单的工具函数,用于判断错误是否由请求取消引起。

通过阅读源码,我们不仅了解了 Axios 取消请求体系的实现原理,还学习到了一些优秀的编程思想和设计模式。例如,使用继承来扩展错误类型,利用 Promise 管理异步操作的状态,以及封装工具函数提高代码的复用性。这些知识可以帮助我们在实际开发中更好地处理请求取消的场景,优化用户体验。

【声明】本内容来自华为云开发者社区博主,不代表华为云及华为云开发者社区的观点和立场。转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息,否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。