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

打印 上一主题 下一主题

主题 1842|帖子 1842|积分 5526

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

一、什么是 AbortController?

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

创建一个 AbortController 实例后,可以通过它的 signal 属性将中止信号通报给相应的 API。当调用 controller.abort() 时,全部使用该信号的操纵都会收到中止通知,并根据设置的逻辑制止执行或抛堕落误。
二、底子用法

  1. // 创建 AbortController 实例
  2. const controller = new AbortController();
  3. // 拿到 signal,并可将其传入需要可中止的 API
  4. const signal = controller.signal;
  5. // 主动触发中止
  6. controller.abort();
复制代码
1. 实例 signal 属性



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



  • 调用后会让该 signal 上监听的全部异步操纵同时中止
  • 可选地,abort(reason) 可以通报一个原因或错误,供业务逻辑作更细粒度的处置惩罚
3. 监听中止事件

  1. controller.signal.addEventListener('abort', () => {
  2.   // 在这里编写中止后的逻辑,例如清理资源或提示用户
  3. });
复制代码
三、实用场景与示例

1. 事件监听器自动清理

我们可以在添加事件监听器时将 signal 作为选项的一部门
一旦 abort() 被调用,会自动移除与该 signal 关联的监听器,从而简化了取消事件监听的流程
  1. const controller = new AbortController();
  2. window.addEventListener('resize', () => {
  3.   console.log('Window resized!');
  4. }, { signal: controller.signal });
  5. // 调用 abort(),会自动移除 resize 监听器
  6. document.getElementById('but').onclick = () => {
  7.   controller.abort();
  8. }
复制代码
1.1. 优势



  • 无需手动保存监听器引用再调用 removeEventListener()
  • 如有多个监听器共用同一个 signal,只需一次 abort() 就能一并移除
2. 在 React 中的应用示例

  1. useEffect(() => {
  2.   const controller = new AbortController();
  3.   window.addEventListener('resize', handleResize, { signal: controller.signal });
  4.   window.addEventListener('hashchange', handleHashChange, { signal: controller.signal });
  5.   window.addEventListener('storage', handleStorageChange, { signal: controller.signal });
  6.   return () => {
  7.     // 调用一次 abort(),所有监听器全部被移除
  8.     controller.abort();
  9.   };
  10. }, []);
复制代码
3. 中止 fetch() 哀求

fetch() 支持通过 signal 中止 HTTP 哀求,是 AbortController 最常见的应用场景之一
  1. async function uploadFile(file) {
  2.   const controller = new AbortController();
  3.   const responsePromise = fetch('/upload', {
  4.     method: 'POST',
  5.     body: file,
  6.     signal: controller.signal,
  7.   });
  8.   return { responsePromise, controller };
  9. }
  10. const { responsePromise, controller } = uploadFile(file);
  11. document.getElementById('but').onclick = () => {
  12.     controller.abort();
  13. }
复制代码


  • 一旦 abort 被触发,fetch() 返回的 Promise 将被拒绝,后端也将收到挂断哀求(具体取决于实际网络环境)
4. Node.js 中止 http 哀求

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

  1. const http = require('http');
  2. const server = http.createServer((req, res) => {
  3.   console.log('收到请求:', req.url);
  4.   res.writeHead(200, { 'Content-Type': 'text/plain; charset=utf-8' });
  5.   // 模拟长时间响应:每 500ms 输出一段文字,共输出 50 次
  6.   let count = 0;
  7.   const intervalId = setInterval(() => {
  8.     if (count < 50) {
  9.       res.write(`数据块 #${count}\n`);
  10.       count++;
  11.     } else {
  12.       clearInterval(intervalId);
  13.       res.end('响应全部完成\n');
  14.     }
  15.   }, 500);
  16.   req.on('close', () => {
  17.     console.log('客户端连接关闭,停止发送数据');
  18.     clearInterval(intervalId);
  19.   });
  20. });
  21. const PORT = 3000;
  22. server.listen(PORT, () => {
  23.   console.log(`服务器已启动,监听端口 ${PORT}`);
  24. });
复制代码
4.2. controller.js

  1. const http = require('http');
  2. function makeAbortableRequest() {
  3.   const controller = new AbortController();
  4.   const { signal } = controller;
  5.   const req = http.get(
  6.     'http://localhost:3000',
  7.     { signal },
  8.     (res) => {
  9.       console.log('已连接到服务器,响应状态:', res.statusCode);
  10.       res.on('data', (chunk) => {
  11.         console.log('收到数据块:', chunk.toString());
  12.       });
  13.       res.on('end', () => {
  14.         console.log('响应结束');
  15.       });
  16.     }
  17.   );
  18.   req.on('error', (err) => {
  19.     console.error('请求错误:', err.message || err);
  20.   });
  21.   setTimeout(() => {
  22.     console.log('5 秒时间到,准备中止请求...');
  23.     controller.abort();
  24.   }, 5000);
  25. }
  26. makeAbortableRequest();
复制代码
5. 制止流操纵



  • 可写流

    • 对于基于 WritableStream 或者更底层的写操纵,假如支持将 signal 与写操纵关联,当 abort() 被调用时,即可制止写入并执行清理

  • 自界说可中止逻辑

    • 在数据库事件中,自行监听 signal 的 abort 事件往返滚事件或抛出特定错误,都能让流程变得更灵活

  1. async function example() {
  2.   const abortController = new AbortController();
  3.   const stream = new WritableStream({
  4.     write(chunk, sinkController) {
  5.       console.log('正在写入:', chunk);
  6.     },
  7.     close() {
  8.       console.log('写入完成');
  9.     },
  10.     abort(reason) {
  11.       console.warn('写操作被中止:', reason);
  12.     }
  13.   });
  14.   const writer = stream.getWriter();
  15.   let i = 1
  16.   const inter = setInterval(async () => {
  17.     await writer.write(`数据块 ${i}`);
  18.     i++
  19.   }, 1000)
  20.   window.currentAbortController = abortController;
  21.   window.currentWriter = writer;
  22.   document.getElementById('cancelButton').onclick = async () => {
  23.     clearInterval(inter)
  24.     if (window.currentAbortController && window.currentWriter) {
  25.       console.log('点击了取消写操作按钮');
  26.       await window.currentWriter.abort('用户主动终止写入');
  27.       window.currentAbortController.abort('用户主动终止写入');
  28.     } else {
  29.       console.log('没有正在进行的写操作');
  30.     }
  31.   };
  32. }
  33. example();
复制代码
四、兼容性



  • 浏览器



  • Node.js
Node.js v16 及以上原生支持在 fetch()、http/https 模块中使用 signal
五、总结与扩展

1. 核心价值



  • AbortController 让我们可以更优雅地中止异步操纵,不再依赖过时的回调或繁琐的清理逻辑。
  • 制止占用资源或等候无效哀求,提升性能和用户体验。
2. 应用场景广泛



  • 事件监听清理、fetch() 哀求取消、Node.js HTTP 哀求中止、数据库事件可回滚……几乎全部异步操纵都能通过一个 signal 实现“一键叫停”。
3. 常见注意点



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

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

x
回复

使用道具 举报

0 个回复

倒序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

王海鱼

论坛元老
这个人很懒什么都没写!
快速回复 返回顶部 返回列表