
es-toolkit AbortError 详解基于 AbortSignal 的中断操作错误处理指南【免费下载链接】es-toolkitA modern JavaScript utility library thats 2-3 times faster and up to 97% smaller, a major upgrade to lodash.项目地址: https://gitcode.com/GitHub_Trending/es/es-toolkitAbortError是 es-toolkit 在error模块中提供的错误类用于统一表示被中断或取消的操作。本文围绕 es-toolkit 的AbortError类讲解其构造函数、默认与自定义错误消息、与AbortSignal的协作方式并结合 delay 等源码实现说明其底层调用链与设计原理帮助你写出可正确识别操作被取消这一异常场景的健壮异步代码。概述为什么需要 AbortError在现代 JavaScript 异步编程中AbortSignal与AbortController是标准化的取消机制。当一个耗时操作如网络请求、定时延迟被用户主动取消或超时中断时我们需要一种方式把这个取消事实以异常的形式传递出来让上层调用方能够区分操作真的失败了网络错误、业务异常操作被人为取消了用户点击了停止按钮、组件卸载、信号超时。es-toolkit 提供AbortError正是为了第二种场景它是一个专门表达操作被中断或取消的错误类语义清晰便于统一捕获与处理。const error new AbortError(message);构造函数与参数new AbortError(message?)AbortError用于表示被中断或取消的操作。它会在类似 debounce 或 delay 这样的操作被AbortSignal取消时被抛出。参数类型说明默认值messagestring可选错误消息文本The operation was aborted返回值AbortError实例表示一次被中断的操作。它继承自Error运行时支持DOMException时继承自DOMException其name属性为AbortError。import { AbortError } from es-toolkit/error; // 使用默认消息创建错误 throw new AbortError(); // 错误消息: The operation was aborted // 使用自定义消息创建错误 throw new AbortError(文件上传已取消); // 错误消息: 文件上传已取消结合 AbortSignal 的典型用法AbortError最常见的应用场景是与AbortSignal配合。es-toolkit 官方文档给出了一个完整的示例在fetchData中执行一个可取消的delay一旦捕获到AbortError就输出操作已取消。import { AbortError, delay } from es-toolkit; async function fetchData(signal: AbortSignal) { try { await delay(1000, { signal }); return 数据加载完成; } catch (error) { if (error instanceof AbortError) { console.log(操作已取消); } throw error; } } const controller new AbortController(); controller.abort(); // 取消操作 await fetchData(controller.signal); // 抛出 AbortError这段代码有两个关键点用instanceof AbortError做类型收窄在catch中先判断是否为取消导致的异常再决定是吞掉还是继续向上抛出。非取消类错误仍会通过throw error传播保证业务异常不会被误判为取消。AbortSignal是标准接口AbortController来自运行时浏览器 / Node.jses-toolkit 的delay接收{ signal }选项并在信号触发abort事件时拒绝reject返回的 Promise。源码级原理AbortError 如何被抛出类的定义AbortError的完整实现非常精简见 src/error/AbortError.tsimport { DOMException } from ../_internal/DOMException.ts; /** * An error class representing an aborted operation. * augments DOMException */ export class AbortError extends DOMException { constructor(message The operation was aborted) { super(message); } }从源码可以看出三个设计事实默认消息message The operation was aborted与文档中的默认值一致继承自DOMException在标准运行时中AbortError是DOMException的子类这也是浏览器规范中取消操作的标准异常类型如fetch被 abort 时抛出的就是DOMException其name为AbortError同时Error也是其原型链上的基类因此instanceof Error恒为truename属性作为DOMException的实例其name属性为AbortError。DOMException 回退机制src/_internal/DOMException.ts 中处理了运行时不支持DOMException的情况例如 Hermes / React Native 等 JavaScript 引擎import { globalThis } from ./globalThis.ts; // Falls back to Error on runtimes without DOMException (e.g. Hermes / React Native). // Type stays typeof DOMException so the emitted .d.ts keeps AbortError extends DOMException. export const DOMException: typeof globalThis.DOMException typeof globalThis.DOMException ! undefined ? globalThis.DOMException : (Error as unknown as typeof globalThis.DOMException);即若运行时存在全局DOMException则直接使用否则回退到Error。这样保证了AbortError在任意环境下都能正常构造与抛出同时让生成的类型声明.d.ts中仍保持AbortError extends DOMException的签名。测试如何验证这些行为src/error/AbortError.spec.ts 用 Vitest 对上述行为做了全面验证new AbortError()是Error的实例未传参时message为The operation was aborted传入自定义消息时message为自定义值运行时存在DOMException时AbortError是其实例通过vi.stubGlobal(DOMException, undefined)模拟 Hermes 等无DOMException的环境时模块仍能正常加载回退后的AbortError依然是Error实例且默认消息不变。delay 中的调用链AbortError的实际抛出来自底层调用方。以 src/promise/delay.ts 为例delay接收{ signal }选项内部实现如下核心逻辑if (signal?.aborted) { return abortError(); } const timeoutId setTimeout(() { signal?.removeEventListener(abort, abortHandler); resolve(); }, ms); signal?.addEventListener(abort, abortHandler, { once: true });其中abortError即reject(new AbortError())。可以看到若传入的signal在调用时已经处于 aborted 状态signal.aborted truedelay立即拒绝并抛出AbortError否则注册一次性abort监听器一旦信号在延迟期间被controller.abort()触发就清除定时器并抛出AbortError正常等到ms毫秒后会移除监听器并resolve()避免内存泄漏。导出路径AbortError通过 src/error/index.ts 导出并在 src/index.ts 中以export * from ./error/index.ts对外暴露。因此你可以有两种导入方式// 按子路径导入 import { AbortError } from es-toolkit/error; // 从主入口导入 import { AbortError, delay } from es-toolkit;与 TimeoutError 的对比es-toolkit 的error模块还提供了TimeoutError见 src/error/TimeoutError.ts两者结构几乎相同但语义不同错误类语义默认消息触发场景AbortError操作被中断 / 取消The operation was abortedAbortSignal被触发如用户取消TimeoutError操作超时The operation was timed out超过设定的时间限制两者都继承自DOMException回退到Error并分别以name AbortError与name TimeoutError区分。实际编码时你可以在同一个catch块中分别判断这两种非业务性异常做出不同的降级处理。最佳实践小结统一出口在封装可取消的异步函数时内部统一throw new AbortError()让调用方用instanceof AbortError识别取消场景区分取消与失败取消应视为预期中的中断通常无需上报错误监控真正的业务异常则应继续抛出复用标准信号AbortSignal可以同时传递给多个操作如delay与真实请求一处controller.abort()即可级联取消兼容多运行时得益于DOMException回退机制AbortError在浏览器、Node.js 以及 Hermes / React Native 等环境都能正常工作。延伸阅读本文主题的英文权威说明见 docs/reference/error/AbortError.md本文日文原版见 docs/ja/reference/error/AbortError.mdAbortError的完整实现src/error/AbortError.ts配套测试用例src/error/AbortError.spec.ts实际抛出AbortError的可取消异步函数src/promise/delay.ts同类错误类TimeoutErrorsrc/error/TimeoutError.tserror模块导出入口src/error/index.ts。【免费下载链接】es-toolkitA modern JavaScript utility library thats 2-3 times faster and up to 97% smaller, a major upgrade to lodash.项目地址: https://gitcode.com/GitHub_Trending/es/es-toolkit创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考