Fetch Multi Signal
Use multiple AbortSignals with the Fetch API
Table of Contents
- Table of Contents
- Features
- Browser Support
- Installation
- Usage
- Example
- Troubleshooting
- Credits
- License
Features
- Adds the
timeoutoption tofetch() - Accepts multiple AbortSignals and aborts if any of them are aborted.
- Works with both
AbortController().signalandAbortSignal.timeout() - Compatible with
fetch()and can be used as a replacement in every call.
Browser Support
![]() |
![]() |
![]() |
![]() |
![]() |
|---|---|---|---|---|
| Latest |
Latest |
Latest |
Latest |
Latest |
Installation
Using npm:
$ npm install fetch-multi-signalUsing yarn:
$ yarn add fetch-multi-signalOnce the package is installed, you can import the function:
import { fetchMS } from 'fetch-multi-signal';You can also use the default export:
import fetchMS from 'fetch-multi-signal';You can use fetchMS() as a drop-in replaement for fetch():
import { fetchMS as fetch } from 'fetch-multi-signal';Usage
Using async/await
const myFunction = async () => {
try {
const res = await fetchMS('url', options);
const json = await res.json();
console.log(json);
} catch (err) {
if (err.name === 'TimeoutError') console.error('Timeout Error');
else if (err.name === 'AbortError') console.error('Abort Error');
} finally {
console.log('done');
}
};Using .then(), .catch(), and .finally()
fetchMS('url', options)
.then((res) => res.json())
.then((json) => console.log(json))
.catch((err) => {
if (err.name === 'TimeoutError') console.error('Timeout Error');
else if (err.name === 'AbortError') console.error('Abort Error');
})
.finally(() => console.log('done'));Options
// 2 sec timeout
fetchMS('url', { timeout: 2000 })
// 2 sec timeout with 2 AbortSignals
const controller1 = new AbortController();
const controller2 = new AbortController();
const signal1 = controller1.signal;
const signal2 = controller2.signal;
fetchMS('url', { timeout: 2000, signals: [signal1, signal2] })
// 2 sec timeout (using AbortSignal.timeout()) with 2 AbortSignals
const controller1 = new AbortController();
const controller2 = new AbortController();
const signal1 = controller1.signal;
const signal2 = controller2.signal;
const timeoutSignal = AbortSignal.timeout(2000);
fetchMS('url', { signal: timeoutSignal, signals: [signal1, signal2] })
// or fetchMS('url', { signal: signal1, signals: [timeoutSignal, signal2] })Note: You can use as many AbortSignals as you want in any order.
TypeScript
import { fetchMS, RequestInitMS } from 'fetch-multi-signal';
const options: RequestInitMS = {
timeout: 2000,
signals: [signal1, signal2],
}
fetchMS('url', options)
// .then(... or await fetchMS(...fetchMSAlt
fetchMSAlt() works the same as fetchMS() but uses setTimeout() to implement the timeout option instead of AbortSignal.timeout()
import { fetchMSAlt } from 'fetch-multi-signal';
fetchMSAlt('url', options)Example
Using with useEffect() hook in React
You can abort the fetch request using a timeout and in the clean-up function:
Using the timeout option
useEffect(() => {
const controller = new AbortController();
fetchMS('url', { timeout: 2000, signal: controller.signal });
//.then(...
return () => controller.abort();
}, []);Using AbortSignal.timeout()
useEffect(() => {
const controller = new AbortController();
const timeoutSignal = AbortSignal.timeout(2000);
fetchMS('url', { signals: [controller.signal, timeoutSignal] });
//.then(...
return () => controller.abort();
}, []);Troubleshooting
1. MaxListenersExceededWarning: Possible EventTarget memory leak detected. 11 abort listeners added to [AbortSignal].
By default, Node.js has maximum listener limit of 10. you can increase the limit depending on your use case:
import events from 'events';
events.setMaxListeners(100);Credits
Inspired by: Proposal: fetch with multiple AbortSignals




