Node AbortController Polyfill
node-abort-controller provides a minimal polyfill for the AbortController and AbortSignal Web APIs, specifically designed for Node.js environments running versions 14.6.x and below. It leverages Node.js's EventEmitter for its implementation. This package is explicitly *not* needed for Node.js versions 14.7.0 and above, as `AbortController` and `AbortSignal` are built-in globals in modern Node.js environments, becoming stable in v15.4.0. The library's current stable version is 3.1.1, and its release cadence is tied to the evolving Node.js core, with updates typically occurring when there are breaking changes or new Node.js versions make the polyfill redundant. Its key differentiator is its lightweight, Node.js-specific approach, aiming to avoid shipping unnecessary polyfills to environments that don't require them, making it ideal for library authors targeting mixed Node.js and modern browser environments where `node-fetch` is also used.
Common errors
-
TypeError: AbortController is not a constructor
cause Attempting to use `require('node-abort-controller')` as a direct constructor call (default import style) after upgrading to v3+, or importing it incorrectly.fixEnsure you are using named imports: `const { AbortController } = require('node-abort-controller');` for CommonJS or `import { AbortController } from 'node-abort-controller';` for ESM. -
npm WARN EBADENGINE Unsupported engine { package: 'node-abort-controller@3.1.0', required: { node: '<14.7.0' }, current: { node: 'vX.Y.Z', npm: 'A.B.C' } }cause Installing `node-abort-controller` in a Node.js environment version 14.7.0 or higher. This package explicitly targets older Node.js versions.fixIf your Node.js version is 14.7.0 or newer, you do not need this package. Remove it and use the native `AbortController` global provided by Node.js. -
FetchError: The user aborted a request.
cause An `AbortController`'s signal was passed to a `fetch` request, and `controller.abort()` was called, leading to a programmatic cancellation. This is often an expected behavior but can be surprising if not explicitly handled.fixWrap the `fetch` call in a `try...catch` block. In the `catch` block, specifically check for `error.name === 'AbortError'` to differentiate a user-initiated or programmatic abort from other types of errors.
Warnings
- breaking Version 3.x removed default exports. `AbortController` and `AbortSignal` must now be imported as named exports for both ES Modules and CommonJS.
- gotcha This package is a polyfill for Node.js versions *below* 14.7.0. For Node.js 14.7.0 and above, `AbortController` and `AbortSignal` are built-in globals. In Node.js >=15.4.0, they are stable. Using this package in newer Node.js versions is unnecessary and may lead to unexpected behavior or larger bundle sizes.
- gotcha This package is specifically designed for Node.js environments and should NOT be used for browser-side polyfilling. For browser applications, especially those supporting legacy browsers, use packages like `abort-controller` or `whatwg-fetch` which provide more comprehensive polyfills.
- gotcha When an `AbortSignal` is triggered, the associated asynchronous operation (e.g., a `fetch` request) will throw an `AbortError`. It is crucial to catch this specific error to prevent application crashes and differentiate between a graceful cancellation and other network or operational failures.
Install
-
npm install node-abort-controller -
yarn add node-abort-controller -
pnpm add node-abort-controller
Imports
- AbortController
const AbortController = require('node-abort-controller');import { AbortController } from 'node-abort-controller'; - AbortSignal
import AbortSignal from 'node-abort-controller';
import { AbortController, AbortSignal } from 'node-abort-controller';
Quickstart
import fetch from 'node-fetch';
import { AbortController } from 'node-abort-controller';
const main = async () => {
const controller = new AbortController();
const signal = controller.signal;
// Abort fetch after 500ms. Effectively a timeout
const timeoutId = setTimeout(() => {
console.log('Request timed out, aborting...');
controller.abort();
}, 500);
try {
console.log('Fetching from Google...');
const response = await fetch('https://www.google.com', { signal });
clearTimeout(timeoutId);
if (response.ok) {
console.log(`Successfully fetched Google (Status: ${response.status})`);
// const text = await response.text();
// console.log(text.substring(0, 100) + '...');
} else {
console.error(`Failed to fetch Google (Status: ${response.status})`);
}
} catch (error) {
if (error.name === 'AbortError') {
console.warn('Fetch request was aborted.');
} else {
console.error('Fetch error:', error.message);
}
}
};
main();