I'm playing with [Promise Extensions for JavaScript (prex)](https://github.com/rbuckton/prex#readme) library. I want to extend the standard [Promise class](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise) with cancellation support, similar to how it is [implemented in Bluebird](http://bluebirdjs.com/docs/api/cancellation.html) (i.e., with an optional `oncancel` callback) but using [prex.CancellationToken](https://github.com/rbuckton/prex/blob/master/docs/cancellation.md#class-cancellationtoken). Here is a draft that can be run with NodeJS, please help improving it: const prex = require('prex'); // CancellablePromise class CancellablePromise extends Promise { constructor(executor, token) { console.log('CancellablePromise::constructor'); if (!token) { // no token supplied, just delegate to the parent class super(executor); return; } super((resolve, reject) => { let reg = null; function unregister() { // unregister cancellation callback if (reg) { reg.unregister(); reg = null; } } function resoveForwarder(v) { unregister(); resolve(v); } function rejectForwarder(e) { unregister(); reject(e); } function oncancelRegistrar(oncancel) { if (!oncancel) throw new Error('oncancel'); // register the cancellation callback reg = token.register(() => { // throw and catch for the extended error info try { token.throwIfCancellationRequested(); } catch (e) { // the token cancellation callback is synchronous // (upon `CancellationTokenSource.cancel`), // but we aim to invoke oncancel asynchronously Promise.resolve().finally(() => { unregister(); oncancel(e); }); } }); } // executor can call `oncancelRegistrar(oncancel)` to // provide its callback to be used for clean up executor(resoveForwarder, rejectForwarder, oncancelRegistrar); }); } } // delayWithCancellation using CancellablePromise function delayWithCancellation(timeoutMs, token) { console.log('delayWithCancellation'); return new CancellablePromise((resolve, reject, oncancel) => { token.throwIfCancellationRequested(); const id = setTimeout(resolve, timeoutMs); oncancel(e => { clearTimeout(id); reject(e); }); }, token); } // main async function main() { const tokenSource = new prex.CancellationTokenSource(); setTimeout(() => tokenSource.cancel(), 1500); // cancel after 1500ms var token = tokenSource.token; await delayWithCancellation(2000, token); console.log("successfully delayed."); // we should not be here } main().catch(e => console.log(e));