Resolve it from anywhere.
defer() returns the promise with its resolve, reject and cancel outside the callback. Made for events, queues and tests.
Promises you can actually control.
Native promises can't be canceled. Their status can't be tracked. Once started, they run to completion. Always.
import { CancelablePromise } from 'easy-cancelable-promise';
// If you know this...
const native = new Promise((resolve, reject) => {
// ...
});
// You know this!
const cancelable = new CancelablePromise((resolve, reject, { onCancel }) => {
// ...
});import { CancelablePromise } from 'easy-cancelable-promise';
const fetchUser = new CancelablePromise(
async (resolve, reject, { onCancel }) => {
const controller = new AbortController();
onCancel(() => controller.abort());
const user = await fetch('/api/user', { signal: controller.signal }).then(
(res) => res.json(),
);
resolve(user);
},
);
// User navigated? Just cancel it.
fetchUser.cancel('User navigated away');The same work runs in a native promise and in a CancelablePromise. Press Stop. With the native promise you can only stop listening: every remaining step still runs. The CancelablePromise is told to stop, and it does.
Open the full exampleThis runs in your browser, against the same package files that are published to npm.
Loading the live example…
Loading the live example…
The core class that extends native Promise with cancellation and lifecycle management.
See every utilityimport { CancelablePromise } from 'easy-cancelable-promise';
new CancelablePromise(
(
resolve,
reject,
{ cancel, onCancel, reportProgress, status, isCanceled, isPending },
) => {
// ✅ cancel: Cancel from inside
cancel('Internal cancellation');
// ✅ onCancel: Subscribe to cancellation
const cleanup = onCancel((reason) => {
console.log('Canceled:', reason);
});
// ✅ reportProgress: Report progress
reportProgress(50); // 50% complete
// ✅ status: Get current status
console.log(status()); // 'pending'
// ✅ isCanceled: Check if canceled
if (isCanceled()) return;
// ✅ isPending: Check if still pending
if (isPending()) {
// Continue work
}
},
);Loading the live example…
Loading the live example…
A native promise says one thing, at the end. A CancelablePromise reports while it works, and whoever holds it can listen. No extra libraries needed, and no second channel to carry around.
Report and track progressThe reports also reach the promises chained from it with then.
groupAsCancelablePromise runs a list of tasks with a concurrency limit and returns one promise. Cancel it and the running tasks stop, and the ones in the queue never start. A queue written with native promises keeps going.
The results come back in the order of the tasks, whichever finishes first.
Loading the live example…
Loading the live example…
Begin with one promise. Reach for the rest only when the application needs it.
defer() returns the promise with its resolve, reject and cancel outside the callback. Made for events, queues and tests.
all, allSettled and race return a promise you can cancel, and canceling it cancels every promise inside.
toCancelablePromise accepts a native promise, a value or a function, and gives back a promise with a status and a cancel method.
No mystery around the small print.
Yes. CancelablePromise extends the native Promise. It works with async / await, then, catch, Promise.all and any code that expects a promise.
Canceling tells everyone to stop waiting. The work stops when the promise has an onCancel listener that stops it: clears the timer, aborts the request. How cancellation works.
A rejection with the reason you passed to cancel. The status of the promise is 'canceled', so a cancellation can be told from a failure, and canceling never causes an unhandled rejection.
No. It has zero dependencies and runs wherever Promise does, in browsers and in Node. Platform and versions.
The promise handles its own cleanup. Cancel from anywhere, anytime.