axios取消请求功能CancelToken原理解析

news2024/9/20 16:27:16

今天在论坛看到一个取消axios请求的功能,具体场景是这样的:前端接口以较短时间间隔请求后端接口刷新状态,接口返回“成功”状态之后还有处于pending状态的请求在排队,如果请求不取消就会导致前端最后获取到的状态出错,这个时候axios的CancelToken取消请求功能就派上用场了。

需要注意的是CancelToken在v0.22.0版本中已经被废弃,不应在新项目中使用,需要使用axios取消请求功能请使用AbortController方式(AbortController是fetch的原生API,axios从v0.22.0版本开始支持),本文仅供学习交流之用。顺嘴提一句,欢迎大家关注我的微信公众号fever code,获取最新技术分享。

技术背景

HTTP请求本身在协议层面上是不可取消的。一旦HTTP请求被发送出去,它就会按照TCP/IP协议栈的规定在网络中传输,直到到达服务器或者因为某种原因(如网络中断)而失败。在这个过程中,客户端(如浏览器或应用程序)无法直接取消或中断这个请求。

然而,在实际应用中,我们可以通过一些机制来间接实现取消HTTP请求的效果。例如,在前端开发中,我们可以使用JavaScript来监听用户的行为(如点击取消按钮),然后在合适的时候停止处理HTTP请求的响应。这并不意味着请求本身被取消了,而是客户端不再关心这个请求的结果,也不会对其进行任何处理。

实现原理

首先,我们知道Axios的请求是基于Promise的,也就是说,每一个Axios请求都会返回一个Promise对象。这个Promise对象代表了异步操作的最终完成(或失败)及其结果值。

然而,Promise的一个问题是它一旦被创建就不能被取消。这意味着一旦你发起了一个Axios请求,你就无法直接取消它。为了解决这个问题,Axios引入了CancelToken

CancelToken是一个对象,它包含一个promise和一个用于取消请求的函数。当你创建一个 CancelToken时,你可以将这个token传递给Axios请求。如果请求仍在等待中,那么调用 CancelToken的取消函数将会拒绝与之关联的Promise,从而取消请求。

CancelToken用法简单介绍

取消请求的需求平时出现的场景不是很多,估计有一部分小伙伴并没有使用过,这里就简单的介绍一下用法

const CancelToken = axios.CancelToken;
const source = CancelToken.source();

axios.get('/user/12345', {
  cancelToken: source.token
}).catch(function (thrown) {
  if (axios.isCancel(thrown)) {
    console.log('Request canceled', thrown.message);
  } else {
    // 处理错误
  }
});

axios.post('/user/12345', {
  name: 'new name'
}, {
  cancelToken: source.token
})

// 取消请求(message 参数是可选的)
source.cancel('Operation canceled by the user.');

CancelToken原理解析

CancelToken 是 Axios 中的一个重要组件,它允许用户取消未完成的请求。以下是 CancelToken 的简化实现源码:

首先,我们定义 Cancel 类,它表示一个取消操作:

function Cancel(message) {
    // 取消操作的原因(消息)  
    this.message = message;  
}    

// 重写Cancel类的toString方法,用于将取消操作转换为字符串 
Cancel.prototype.toString = function () {
    return 'Cancel' + (this.message ? ': ' + this.message : '');  
};  	  

// 为Cancel类的实例添加一个标记,用于后续识别取消错误 
Cancel.prototype.__CANCEL__ = true;

Cancel 类接收一个消息作为参数,并有一个 toString 方法用于将取消信息转换为字符串。__CANCEL__ 属性是一个标记,用于后续识别取消错误。

接下来,我们定义 CancelToken 类:

function CancelToken(executor) {
    if (typeof executor !== 'function') {
        throw new TypeError('executor must be a function.');  
    }
    
    // 定义一个resolvePromise函数,用于在取消时解析promise  
    var resolvePromise;
    // 创建一个新的Promise对象,这个Promise在取消时会被解析  
    this.promise = new Promise(function promiseExecutor(resolve) {  
        resolvePromise = resolve;
    });  

    // 定义一个变量token,用于引用当前的CancelToken实例  
    var token = this;
    // 调用executor函数,并传入一个取消函数作为参数  
    executor(function cancel(message) {
        // 如果token已经被取消过,则不再重复取消 
        if (token.reason) {
            // CancelToken 已经取消过,不应该再取消  
            return;  
        }
        // 将取消的原因(Cancel实例)存储在token的reason属性中  
        token.reason = new Cancel(message); 
        // 调用resolvePromise函数,解析this.promise为取消的原因 
        resolvePromise(token.reason);  
    });  
}  

// 为CancelToken类定义一个方法,用于在请求发送前检查是否已取消 
CancelToken.prototype.throwIfCancelled = function throwIfCancelled() { 
    // 如果token已经被取消(reason属性存在),则抛出取消的原因 
    if (this.reason) {  
        throw this.reason;  
    }  
};  

// 为CancelToken类定义一个静态方法source,用于生成token和取消函数 
CancelToken.source = function source() {  
    var cancel;  
    // 创建一个新的CancelToken实例,并将取消函数作为参数传递给executor
    var token = new CancelToken(function executor(c) { 
        // 将传入的取消函数赋值给cancel变量 
        cancel = c;  
    });
    // 返回一个对象,包含生成的token和取消函数  
    return { token: token, cancel: cancel };  
};

CancelToken 类中:

  • executor 是一个函数,它接收一个取消函数作为参数。当需要取消请求时,调用这个函数。
  • this.promise 是一个新的 Promise 对象,它会在取消函数被调用时解析(resolve)为 Cancel 实例。
  • token.reason 存储取消的原因(Cancel 实例)。

CancelToken.source 方法是一个静态方法,它返回一个对象,该对象包含 tokencancel 函数。这为用户提供了一个方便的方式来获取 CancelToken 和取消函数。

现在,当用户想要取消请求时,他们会调用 source.cancel 函数,这会触发 CancelToken 中的 executor 函数,进而解析 this.promise 为一个 Cancel 实例。在 Axios 内部,当发送请求时,会检查这个 promise,并在请求被取消时拒绝(reject)相关的 Promise

写在最后:欢迎关注扫码作者微信公众号fever code,获取一手技术分享⛽️
在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1904634.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

C语言实现计算器混合运算(含括号,加减乘除)

功能描述: 实现计算器混合运算基本功能,包括:( )、、-、*、/。 功能很简单,但实现起来还是有一定逻辑难度,因为,混合运算需要考虑优先级。 优先级最高的为:() 其次&a…

LabVIEW干涉仪测向系统

开发了一套基于LabVIEW的软件系统,结合硬件设备,构建一个干涉仪测向实验教学平台。该平台应用于信号处理课程,帮助学生将理论知识与实际应用相结合,深化对信号处理核心概念的理解和应用。 项目背景: 当前信号处理教学…

基于Wireshark和TiWsPC(Wireshark Packet Converter)的Zigbee抓包

前言 介绍几种Zigbee抓包方式: 1. Ubiqua 使用教程网上非常多也非常清晰; 但是Ubiqua是收费软件,较贵; 我安装过了,费好多事,没安装成功。 2. Killerbee套件 https://github.com/riverloopsec/killerbe…

TB作品】51单片机 Proteus仿真 51单片机SPI显示OLED字符驱动

// GND 电源地 // VCC 接5V或3.3v电源 // D0 P1^4(SCL) // D1 P1^3(SDA) // RES 接P12 // DC 接P11 // CS 接P10 OLED显示接口与控制实验报告 背景 OLED(有机发光二极管)显示器由于其高对比度、低功耗和…

【论文通读】RuleR: Improving LLM Controllability by Rule-based Data Recycling

RuleR: Improving LLM Controllability by Rule-based Data Recycling 前言AbstractMotivationSolutionMethodExperimentsConclusion 前言 一篇关于提升LLMs输出可控性的短文,对SFT数据以规则的方式进行增强,从而提升SFT数据的质量,进而间接帮…

关于模拟数字模块认知

工业上常见信号分类 PLC控制系统主要是电信号 电信号分为数字信号和模拟信号 PLC系统中有数字量模块DO/DI,模拟量AO/AI。(O为输出,I为输入) 在模块应用中,注意前连接器要和冷压端子相匹配。前连接器可理解为接插件&am…

Go:hello world

开启转职->Go开发工程师 下面是我的第一个go的程序 在上面的程序介绍: 1、package main 第一行代码package main定义了包名。必须在源文件中非注释的第一行指明这个文件属于哪个包,如:package main。package main表示一个可独立执行的程…

用HttpURLConnection复现http响应码405

目录 使用GET方法,访问GET接口,服务端返回405使用GET方法,访问POST接口,服务端返回405使用POST方法,访问GET接口,服务端返回405 使用GET方法,访问GET接口,服务端返回405 发生场景&a…

Polkadot(DOT)即将爆雷?治理无能还歧视亚洲!资金将在两年内耗尽!是下一个FTX吗?

近期,关于Polkadot(DOT)生态圈的一系列负面消息引发了业界和投资者的广泛关注。从高昂的营销开支、缺乏实际业务亮点,再到治理问题和种族歧视指控,Polkadot似乎正面临着严峻的危机。业内人士警告,Polkadot的财政状况堪忧&#xff…

【机器学习】机器学习与时间序列分析的融合应用与性能优化新探索

文章目录 引言第一章:机器学习在时间序列分析中的应用1.1 数据预处理1.1.1 数据清洗1.1.2 数据归一化1.1.3 数据增强 1.2 模型选择1.2.1 自回归模型1.2.2 移动平均模型1.2.3 长短期记忆网络1.2.4 卷积神经网络 1.3 模型训练1.3.1 梯度下降1.3.2 随机梯度下降1.3.3 A…

简介空间复杂度

我们承接上一篇博客。我们写了时间复杂度之后,我们就要来介绍一下另一个相关复杂度了。空间复杂度。我觉得大家应该对空间复杂度认识可能比较少一些。我就是这样,我很少看见题目中有明确要求过空间复杂度的。但确实有这个是我们不可忽视的,所…

el-date-picker 设置默认值为当前日期

this.listQuery.Date new Date().toISOString().substr(0, 10); <el-date-picker v-model"listQuery.Date" format"yyyy-MM-dd" value-format"yyyy-MM-dd" type"date" placeholder"选择日期" change"getList()&qu…

电源纹波相关

什么是纹波&#xff1f;什么是噪声&#xff1f; 这种叠加在直流稳定量上的交流分量就称为纹波。 纹波的危害 电源纹波能影响设备性能和稳定性 纹波会导致电器上产生谐波&#xff0c;降低电源的使用效率&#xff1b; 高频电源纹波可能会产生浪涌电压或电流&#xff0c;影响设…

【解决方案】笔记本电脑屏幕亮度调节失效(Dell G15 5510 使用Fn调节)

目前解决方案&#xff1a;使用驱动总裁&#xff08;其他的驱动安装软件应该也可以&#xff0c;个人觉得这个好用&#xff09;&#xff0c;更新显卡驱动即可。如图所示本人更新了Intel UHD Graphics核显驱动&#xff0c;功能回复正常。 使用Fn快捷键调节亮度如图所示&#xff0…

Zabbix 的部署和自定义监控内容

前言 一个完整的项目的业务架构包括 客户端 -> 防火墙 -> 负载均衡层&#xff08;四层、七层 LVS/HAProxy/nginx&#xff09; -> Web缓存/应用层&#xff08;nginx、tomcat&#xff09; -> 业务逻辑层(php/java动态应用服务) -> 数据缓存/持久层&#xff08;r…

使用AOP思想实现开闭原则下的流水日志输出

主要实现思想&#xff1a; 通过实现Convert接口来抽取公共组件&#xff0c;获取想要的标准模型。 现在有两个订单场景&#xff0c;一个保存订单&#xff0c;一个为更新订单。构造如下的服务类&#xff1a; import org.springframework.stereotype.Service;Service public clas…

VSCode神仙插件——CodeSnap (好看的代码截图)

1 安装 2 使用 选中要截图的代码,右键 此时右侧会出现代码截图的预览图 如果要将截图保存到本地,则点击上图红色框中的图标 也可以点击下面截的图,CtrlC复制,然后就可以CtrlV粘贴到其他应用程序里了

Pycharm python解释器 unsupported python 3.1 解决

Pycharm 环境 unsupported python 3.1解决 1. 问题重现2. 原因分析3. 解决方法 1. 问题重现 之前使用Pycharm 2024.1.1的时候&#xff0c;环境配置的Python 3.11.9&#xff0c;现在改成使用Pycharm 2020.2.2&#xff0c;结果Python解释器显示“unsupported python 3.1”&#…

GIT 使用相关技巧记录

目录 1、commit 用户信息变更 全局用户信息&#xff08;没有特殊配置的情况下默认直接用全局信息&#xff09; 特定仓库用户信息&#xff08;只针对于当前项目&#xff09; 方法一&#xff1a;修改config文件 方法二&#xff1a;命令方式 2、idea同一代码推向多个远端仓库…

如何在Ubuntu环境下使用加速器配置Docker环境

一、安装并打开加速器 这个要根据每个加速器的情况来安装并打开&#xff0c;一般是会开放一个代理端口&#xff0c;比如1087 二、安装Docker https://docs.docker.com/engine/install/debian/#install-using-the-convenience-script 三、配置Docker使用加速器 3.1 修改配置…