AbortController:让异步操作随时说停就停

AbortController:让异步操作随时说停就停

一、什么是 AbortController?

AbortController 是 JavaScript 在浏览器和部分 Node.js 环境中提供的全局类,用来中止正在进行或待完成的异步操作(如 fetch() 请求、事件监听、可写流、数据库事务等)。通过它,我们可以在需要的时候自由地终止这些操作,避免不必要的开销或冗长的等待。

1. 核心思路

创建一个 AbortController 实例后,可以通过它的 signal 属性将中止信号传递给相应的 API。当调用 controller.abort() 时,所有使用该信号的操作都会收到中止通知,并根据设置的逻辑停止执行或抛出错误。

二、基础用法

// 创建 AbortController 实例
const controller = new AbortController();// 拿到 signal,并可将其传入需要可中止的 API
const signal = controller.signal;// 主动触发中止
controller.abort();

1. 实例 signal 属性

  • signal 是一个 AbortSignal 实例,可被用于任何支持中止的 API(如 fetch()、事件监听器等)
  • 一旦 abort() 被调用,signal 就会触发 abort 事件,标记为已中止

2. 实例 abort() 方法

  • 调用后会让该 signal 上监听的所有异步操作同时中止
  • 可选地,abort(reason) 可以传递一个原因或错误,供业务逻辑作更细粒度的处理

3. 监听中止事件

controller.signal.addEventListener('abort', () => {// 在这里编写中止后的逻辑,例如清理资源或提示用户
});

三、实用场景与示例

1. 事件监听器自动清理

我们可以在添加事件监听器时将 signal 作为选项的一部分

一旦 abort() 被调用,会自动移除与该 signal 关联的监听器,从而简化了取消事件监听的流程

const controller = new AbortController();window.addEventListener('resize', () => {console.log('Window resized!');
}, { signal: controller.signal });// 调用 abort(),会自动移除 resize 监听器
document.getElementById('but').onclick = () => {controller.abort();
}
1.1. 优势
  • 无需手动保存监听器引用再调用 removeEventListener()
  • 若有多个监听器共用同一个 signal,只需一次 abort() 就能一并移除

2. 在 React 中的应用示例

useEffect(() => {const controller = new AbortController();window.addEventListener('resize', handleResize, { signal: controller.signal });window.addEventListener('hashchange', handleHashChange, { signal: controller.signal });window.addEventListener('storage', handleStorageChange, { signal: controller.signal });return () => {// 调用一次 abort(),所有监听器全部被移除controller.abort();};
}, []);

3. 中止 fetch() 请求

fetch() 支持通过 signal 中止 HTTP 请求,是 AbortController 最常见的应用场景之一

async function uploadFile(file) {const controller = new AbortController();const responsePromise = fetch('/upload', {method: 'POST',body: file,signal: controller.signal,});return { responsePromise, controller };
}const { responsePromise, controller } = uploadFile(file);document.getElementById('but').onclick = () => {controller.abort();
}
  • 一旦 abort 被触发,fetch() 返回的 Promise 将被拒绝,后端也将收到挂断请求(具体取决于实际网络环境)

4. Node.js 中止 http 请求

在新版 Node.js 环境中(v16+),AbortSignal 同样可以应用于内置的 http 或 https 模块中,以取消请求或响应读取。用法与浏览器环境基本一致

4.1. server.js
const http = require('http');const server = http.createServer((req, res) => {console.log('收到请求:', req.url);res.writeHead(200, { 'Content-Type': 'text/plain; charset=utf-8' });// 模拟长时间响应:每 500ms 输出一段文字,共输出 50 次let count = 0;const intervalId = setInterval(() => {if (count < 50) {res.write(`数据块 #${count}\n`);count++;} else {clearInterval(intervalId);res.end('响应全部完成\n');}}, 500);req.on('close', () => {console.log('客户端连接关闭,停止发送数据');clearInterval(intervalId);});
});const PORT = 3000;
server.listen(PORT, () => {console.log(`服务器已启动,监听端口 ${PORT}`);
});
4.2. controller.js
const http = require('http');function makeAbortableRequest() {const controller = new AbortController();const { signal } = controller;const req = http.get('http://localhost:3000',{ signal },(res) => {console.log('已连接到服务器,响应状态:', res.statusCode);res.on('data', (chunk) => {console.log('收到数据块:', chunk.toString());});res.on('end', () => {console.log('响应结束');});});req.on('error', (err) => {console.error('请求错误:', err.message || err);});setTimeout(() => {console.log('5 秒时间到,准备中止请求...');controller.abort();}, 5000);
}makeAbortableRequest();

5. 终止流操作

  • 可写流
    • 对于基于 WritableStream 或者更底层的写操作,如果支持将 signal 与写操作关联,当 abort() 被调用时,即可停止写入并执行清理
  • 自定义可中止逻辑
    • 在数据库事务中,自行监听 signal 的 abort 事件来回滚事务或抛出特定错误,都能让流程变得更灵活
async function example() {const abortController = new AbortController();const stream = new WritableStream({write(chunk, sinkController) {console.log('正在写入:', chunk);},close() {console.log('写入完成');},abort(reason) {console.warn('写操作被中止:', reason);}});const writer = stream.getWriter();let i = 1const inter = setInterval(async () => {await writer.write(`数据块 ${i}`);i++}, 1000)window.currentAbortController = abortController;window.currentWriter = writer;document.getElementById('cancelButton').onclick = async () => {clearInterval(inter)if (window.currentAbortController && window.currentWriter) {console.log('点击了取消写操作按钮');await window.currentWriter.abort('用户主动终止写入');window.currentAbortController.abort('用户主动终止写入');} else {console.log('没有正在进行的写操作');}};
}example();

四、兼容性

  • 浏览器

  • Node.js

Node.js v16 及以上原生支持在 fetch()、http/https 模块中使用 signal

五、总结与扩展

1. 核心价值

  • AbortController 让我们可以更优雅地中止异步操作,不再依赖过时的回调或繁琐的清理逻辑。
  • 避免占用资源或等待无效请求,提升性能和用户体验。

2. 应用场景广泛

  • 事件监听清理、fetch() 请求取消、Node.js HTTP 请求中止、数据库事务可回滚……几乎所有异步操作都能通过一个 signal 实现“一键叫停”。

3. 常见注意点

  • 在代码中使用多条 fetch() 时,务必区分好各自的 controller,或使用 AbortSignal.any() 合并控制。
  • 对于中止错误,需要在 .catch() 或事件监听中显式处理,防止误认为是网络异常或其他错误。

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

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

相关文章

机器学习 从入门到精通 day_04

1. 决策树-分类 1.1 概念 1. 决策节点 通过条件判断而进行分支选择的节点。如&#xff1a;将某个样本中的属性值(特征值)与决策节点上的值进行比较&#xff0c;从而判断它的流向。 2. 叶子节点 没有子节点的节点&#xff0c;表示最终的决策结果。 3. 决策树的…

C++ Primer (第五版)-第十三章 拷贝控制

文章目录 概述13.1拷贝、赋值与销毁合成拷贝构造函数拷贝初始化参数和返回值拷贝初始化的限制编译器可以绕过拷贝构造函数拷贝运算符析构函数三/五原则使用default阻止拷贝合成的拷贝控制成员可能是删除的 private拷贝控制拷贝控制和资源管理行为像值的类类值拷贝赋值运算符定义…

Vue el-from的el-form-item v-for循环表单如何校验rules(一)

实际业务需求场景&#xff1a; 新增或编辑页面&#xff08;基础信息表单&#xff0c;一个数据列表的表单&#xff09;&#xff0c;数据列表里面的表单数是动态添加的。数据可新增、可删除&#xff0c;在表单保存前&#xff0c;常常需要做表单必填项的校验&#xff0c;校验通过以…

测试100问:http和https的区别是什么?

哈喽&#xff0c;大家好&#xff0c;我是十二&#xff0c;今天给大家分享的问题是&#xff1a;http和https的区别是什么&#xff1f; 首先我们要知道 HTTP 协议传播的数据都是未加密的&#xff0c;也就是明文的&#xff0c;因此呢使用 http协议传输一些隐私信息也就非常不安全&…

YOLOv3超详细解读(三):源码解析:数据处理模块

一、概述 YOLOv3&#xff08;You Only Look Once v3&#xff09;是一种高效的目标检测算法&#xff0c;其数据处理模块是训练和推理流程的核心部分。本文将深入分析Ultralytics团队基于PyTorch实现的YOLOv3源码中的数据处理模块&#xff0c;重点探讨数据加载、预处理和数据增强…

每日算法(双指针算法)(Day 1)

双指针算法 1.算法题目&#xff08;移动零&#xff09;2.讲解算法原理3.编写代码 1.算法题目&#xff08;移动零&#xff09; 2.讲解算法原理 数组划分&#xff0c;数组分块&#xff08;快排里面最核心的一步&#xff09;只需把0改为tmp 双指针算法&#xff1a;利用数组下标来…

2025蓝桥杯python A组省赛 题解

真捐款去了&#xff0c;好长时间没练了&#xff0c;感觉脑子和手都不转悠了。 B F BF BF 赛时都写假了&#xff0c; G G G 也只写了爆搜。 题解其实队友都写好了&#xff0c;我就粘一下自己的代码&#xff0c;稍微提点个人的理解水一篇题解 队友题解 2025蓝桥杯C A组省赛 题…

测试基础笔记第四天(html)

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 html介绍1. 介绍2.骨架标签3.常用标签标题标签段落标签超链接标签图片标签换行和空格标签布局标签input标签&#xff08;变形金刚&#xff09;form标签列表标签 htm…

10 穴 汽车连接器的15个设计特点

汽车行业严重依赖卓越的电气系统来确保功能和可靠性。这些系统的关键组件是 10 腔连接器&#xff0c;它为布线和信号传输提供解决方案。制造商和工程师必须仔细评估这些连接器的设计特性&#xff0c;以优化性能和安全性。 本博客研究了汽车 10 腔连接器的 15 个设计特征&#…

Summary

一、数据结构 1.1 哈希 主要是HashMap和HashSet&#xff1b;其中HashSet底层是一个HashMap属性。 // 获取HashMap元素,HashSet均不支持 map.keySet (); // Set<k> map.values (; // Collection<V> map.entrySet();//Set<Map.Entry<K,V>> for (Map.E…

【Leetcode-Hot100】最小覆盖子串

题目 解答 想到使用双指针哈希表来实现&#xff0c;双指针的left和right控制实现可满足字符串。 class Solution(object):def minWindow(self, s, t):""":type s: str:type t: str:rtype: str"""len_s, len_t len(s), len(t)hash_map {}for…

Flutter 播放利器:`media_kit` 的详细介绍与使用指南

在 Flutter 项目中实现音视频播放&#xff0c;开发者过去主要依赖如 video_player、just_audio 等第三方库&#xff0c;但这些库或多或少存在一些局限性&#xff0c;比如平台兼容性差、定制能力不足、播放格式有限等问题。 而 media_kit 是近年崛起的一款全平台音视频播放解决…

4.14【Q】pc homework3

我正在学习并行计算&#xff0c;解决这个问题&#xff1f;详细解释&#xff0c;越细节越好 我正在学习并行计算&#xff0c;“首次允许在 taskloop 构造中使用 reduction 子句&#xff0c;并引入了 task_reduction&#xff08;用于 taskgroup 构造&#xff09;和 in_reduction&…

ArrayList vs LinkedList,HashMap vs TreeMap:如何选择最适合的集合类?

精心整理了最新的面试资料和简历模板&#xff0c;有需要的可以自行获取 点击前往百度网盘获取 点击前往夸克网盘获取 在 Java 开发中&#xff0c;集合类的选择直接影响程序的性能和代码的可维护性。不同的数据结构适用于不同的场景&#xff0c;盲目使用可能导致内存浪费、性能…

大模型训练显存压缩实战:ZeRO-3 vs 梯度累积 vs 量化混合策略

一、显存瓶颈的本质与挑战 大模型训练面临的核心矛盾是模型参数量指数级增长与GPU显存容量线性提升之间的鸿沟。以175B参数模型为例&#xff0c;其显存消耗主要来自三个方面&#xff1a; 参数存储‌&#xff1a;FP32精度下需700GB显存‌梯度缓存‌&#xff1a;反向传播产生的…

边缘计算与隐私计算的融合:构建数据经济的“隐形护盾“

在数据成为核心生产要素的今天&#xff0c;边缘计算与隐私计算的交汇正在重塑技术生态。这并非简单的技术叠加&#xff0c;而是一场关于数据主权、算力分配与信任机制的深度博弈。本文将从"数据流动的拓扑学"视角&#xff0c;探讨二者融合如何重构数字社会的基础设施…

Obsidian 文件夹体系构建 -INKA

Obsidian 文件夹体系构建 -INKA 本篇文章主要分享一下自己折腾学习实践过的 INKA 框架方法。原地址&#xff1a;Obsidian文件夹体系构建–INKA。 文章目录 Obsidian 文件夹体系构建 -INKA前言INKA简介INKA 理论最佳实践实际应用 反思 前言 上文 Obsidian文件夹体系构建-ACCES…

ocr-不动产权识别

目录 一、在阿里云申请ocr识别服务 二、创建springboot项目 三、后续 一、在阿里云申请ocr识别服务 在线体验&#xff1a;房产证图片上传 [阿里官方]不动产权证OCR文字识别_API专区_云市场-阿里云 (aliyun.com) 可以选择一毛500次这个 当然也可以白嫖100 下面有个在线调试…

LeetCode算法题(Go语言实现)_47

题目 给你一个 m x n 的迷宫矩阵 maze &#xff08;下标从 0 开始&#xff09;&#xff0c;矩阵中有空格子&#xff08;用 ‘.’ 表示&#xff09;和墙&#xff08;用 ‘’ 表示&#xff09;。同时给你迷宫的入口 entrance &#xff0c;用 entrance [entrancerow, entrancecol…

The Strict Teacher (Hard Version) 去除无效的干扰!巧妙转化

文章目录 The Strict Teacher (Hard Version) 思考问题&#xff01;那么多个人抓一个人&#xff0c;是否是每一个人都是对于最优策略的答案是有贡献的&#xff1f;答案是否定的&#xff0c;其实问题可以简化为三种情况&#xff1a; 所有的老师都在大卫的右边&#xff0c;…