Skip to main content

How to cancel a promise?

Why a promise cannot be canceled directly

When you create a promise, for example:

javascript
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).

javascript
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:

  • AbortController creates a control object;
  • signal is passed into fetch;
  • when controller.abort() is called, the request is aborted, and the promise rejects with AbortError.

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.

javascript
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:

javascript
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:

javascript
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:

javascript
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

MethodWhat it doesReal cancellationGood for
AbortControllerAborts operations that support signalsYesfetch, APIs with signal
makeCancellable()Creates a wrapper with a flagNo (logical cancellation)Custom promises
Cancellation flagChecks "cancelled" manuallyNoLoops, async functions
Promise.race()Settles with whichever promise winsNo, but convenientTimeouts, 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 ready
Premium

A concise answer to help you respond confidently on this topic during an interview.