defer and DeferredPromise
Create a CancelablePromise whose resolve, reject and utilities live outside its callback, for events, queues and tests.
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.
| Property | What it is |
|---|---|
promise | The CancelablePromise |
resolve | Resolves the promise |
reject | Rejects the promise |
cancel | Cancels the promise. Returns the promise |
onCancel | Registers a cancel listener. Returns a function to remove it |
onProgress | Registers a progress listener. Returns a function to remove it |
reportProgress | Sends progress to the listeners |
status | Returns the current status |
isPending | true while the promise is not settled |
isCanceled | true 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
- Static helpers
- Testing:
deferis the simplest way to hand a controlled promise to the code under test.