Skip to content
easy-cancelable-promise

defer and DeferredPromise

Create a CancelablePromise whose resolve, reject and utilities live outside its callback, for events, queues and tests.

GuideTypeScriptTry an example

A promise with its controls outside

Sometimes the code that settles a promise is not the code that creates it: an event handler, a message from another window, a test. defer returns the promise together with its controls.

basic.ts
import { defer } from 'easy-cancelable-promise';

export async function basic() {
  const deferred = defer<string>();

  // the promise is here, the controls are separate
  setTimeout(() => deferred.resolve('Hello world!'), 10);

  return deferred.promise; // resolves with 'Hello world!'
}

What defer returns

defer<T>() returns a DeferredPromise<T>: the promise, resolve, reject, and the same utilities the callback of a CancelablePromise receives.

PropertyWhat it is
promiseThe CancelablePromise
resolveResolves the promise
rejectRejects the promise
cancelCancels the promise. Returns the promise
onCancelRegisters a cancel listener. Returns a function to remove it
onProgressRegisters a progress listener. Returns a function to remove it
reportProgressSends progress to the listeners
statusReturns the current status
isPendingtrue while the promise is not settled
isCanceledtrue after the promise was canceled
utils.ts
import { defer } from 'easy-cancelable-promise';

export function utils() {
  const deferred = defer<number>();

  const before = [deferred.status(), deferred.isPending(), deferred.isCanceled()];

  // the same utilities the callback of a CancelablePromise receives
  const unsubscribe = deferred.onCancel((reason) => console.log(reason));

  deferred.onProgress((percentage) => console.log(percentage));
  deferred.reportProgress(50);

  unsubscribe();
  deferred.cancel('Not needed');

  return [before, deferred.status(), deferred.promise.status];
  // [['pending', true, false], 'canceled', 'canceled']
}

Resolve from an event

A deferred promise turns an event into something you can await, with a timeout that cancels it.

event.ts
import { defer } from 'easy-cancelable-promise';

export function waitForClick(button: HTMLButtonElement, timeout = 30_000) {
  const deferred = defer<MouseEvent>();

  const onClick = (event: MouseEvent) => deferred.resolve(event);
  const timer = setTimeout(() => deferred.cancel('Timeout'), timeout);

  button.addEventListener('click', onClick);

  // however it ends, remove what was added
  deferred.promise
    .finally(() => {
      clearTimeout(timer);
      button.removeEventListener('click', onClick);
    })
    .catch(() => {});

  return deferred.promise;
}

Next

Documentation
↑↓ Navigate ↵ Open Esc Closeeasy-cancelable-promise docs
Get started

Promises you can actually control.