How to cancel a promise?
Why a promise cannot be canceled directly
When you create a promise, for example:
const promise = new Promise((resolve) => {
setTimeout(() => resolve('done'), 5000);
});It starts running immediately (from the moment the constructor is called),
and there is no standard mechanism to "stop" the timer or fetch.
In other words, a promise is not a "stream", but a wrapper over a result that will eventually arrive.
Ways to implement cancellation
1. Use AbortController (the built-in standard)
This is the most modern and "correct" way to cancel asynchronous operations,
especially network ones (fetch).
const controller = new AbortController();
const { signal } = controller;
fetch('/data', { signal })
.then(response => response.json())
.then(data => console.log('Success:', data))
.catch(err => {
if (err.name === 'AbortError') {
console.log('Request cancelled');
} else {
console.error('Error:', err);
}
});
// cancel after 2 seconds
setTimeout(() => controller.abort(), 2000);What happens:
AbortControllercreates a control object;signalis passed intofetch;- when
controller.abort()is called, the request is aborted, and the promise rejects withAbortError.
Works with:
fetch()ReadableStream,Response,Request- many libraries that support signals (Axios, Deno, Node 18+, and others)
2. Create a "cancellable" promise manually
You can wrap a regular promise in a structure that supports cancellation.
function makeCancellable(promise) {
let isCancelled = false;
const wrapped = new Promise((resolve, reject) => {
promise
.then((val) => (isCancelled ? reject({ cancelled: true }) : resolve(val)))
.catch((error) => (isCancelled ? reject({ cancelled: true }) : reject(error)));
});
return {
promise: wrapped,
cancel() {
isCancelled = true;
},
};
}Usage example:
const { promise, cancel } = makeCancellable(
new Promise((resolve) => setTimeout(() => resolve('Done'), 5000))
);
promise
.then(console.log)
.catch((e) => {
if (e.cancelled) console.log('Cancelled by the user');
});
setTimeout(cancel, 2000);After 2 seconds the promise will be "cancelled".
Important: this is a logical cancellation,
the operation itself (for example, setTimeout or fetch) still continues.
3. Use a flag inside an async function
If you have an async function, you can check a "cancelled" flag:
let cancelled = false;
async function runTask() {
for (let i = 0; i < 5; i++) {
if (cancelled) throw new Error('Cancelled');
await new Promise(r => setTimeout(r, 1000));
console.log('Step', i);
}
console.log('Done');
}
const task = runTask();
setTimeout(() => (cancelled = true), 2500);After 2.5 seconds execution stops.
4. Combine with Promise.race() (cancellation through a "race")
You can set up a "race" between the operation and a cancellation timer:
function cancelable(promise, ms) {
const cancel = new Promise((_, reject) =>
setTimeout(() => reject(new Error('Timeout')), ms)
);
return Promise.race([promise, cancel]);
}
cancelable(fetch('/api/data'), 2000)
.then(res => res.json())
.then(console.log)
.catch(console.error);If fetch does not finish within 2 seconds, the promise rejects with a "Timeout" error.
Summary
| Method | What it does | Real cancellation | Good for |
|---|---|---|---|
| AbortController | Aborts operations that support signals | Yes | fetch, APIs with signal |
| makeCancellable() | Creates a wrapper with a flag | No (logical cancellation) | Custom promises |
| Cancellation flag | Checks "cancelled" manually | No | Loops, async functions |
| Promise.race() | Settles with whichever promise wins | No, but convenient | Timeouts, competing tasks |
The bottom-line rule:
You cannot "cancel" a promise in JS directly. But you can cancel the action it represents, using
AbortController, timeouts, or cancellation flags.
Short Answer
Interview readyA concise answer to help you respond confidently on this topic during an interview.