Timing out async work
AbortSignal.timeout()
Baseline newly available
Chrome124
Edge124
Firefox100
Safari16
Features it needs
- AbortSignal.timeout()Newly available
These packages race your promise against a timer and reject when the timer wins. The work carries on in the background, because a promise has no cancel, so a timed-out request still holds its connection and still lands its response. AbortSignal.timeout() returns a signal that aborts itself after the given time, and anything that takes a signal stops for real. AbortSignal.any() combines it with a controller when a timeout and a manual cancel both have to work.
When this applies
Giving a cancellable operation such as fetch a deadline.
The native approach
const response = await fetch(url, { signal: AbortSignal.timeout(5000) });
// A timeout the user can also cancel.
const controller = new AbortController();
const response2 = await fetch(url, {
signal: AbortSignal.any([controller.signal, AbortSignal.timeout(5000)]),
});When the dependency is still right
An answer that always says "the platform covers it" is worse than no answer. These are the cases where this one does not hold.
- What you are timing out takes no AbortSignal. A plain promise from a library with no signal option cannot be aborted, so racing it is still the only option and that race is what p-timeout is.
- You need a specific error, or a fallback value instead of a rejection. AbortSignal.timeout() rejects with a TimeoutError DOMException and offers no hook, where p-timeout takes your own error or resolves with a default.
- The combined signal has to say why it aborted. AbortSignal.any() adopts the reason of whichever signal fired, so telling a timeout from a user cancel means reading signal.reason rather than catching a distinct type.
- You support browsers below Chrome 124, Firefox 100 or Safari 16. AbortSignal.any() landed separately, so check it too if the snippet uses both.