I'm playing with [Promise Extensions for JavaScript (prex)](https://github.com/rbuckton/prex#readme) library and I like it a lot. Amongst other things, this library appears to be a prototype behind the current [ECMA TC39 proposal for cancellation](https://github.com/tc39/proposal-cancellation) and it uses the familiar cancellation token approach, popularized by .NET Task API. 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: const prex = require('prex'); class CancellablePromise extends Promise { constructor(executor, token) { if (!token) { // if no token supplied, just delegate to the parent class super(executor); return; } const observeCancellation = async () => { // prex.Deferred is similar to TaskCompletionSource in .NET const deferred = new prex.Deferred(); executor( deferred.resolve, deferred.reject, cancelListener => deferred.cancelListener = cancelListener); const registration = token.register(() => { try { // capture the CancelError token.throwIfCancellationRequested(); } catch (cancelError) { try { // the token cancellation callback is synchronous, // and so is the executor-provided cancelListener callback deferred.cancelListener && deferred.cancelListener(cancelError); // reject here if cancelListener has not resolved/rejected it deferred.reject(cancelError); } catch (error) { // in case cancelListener throws deferred.reject(error); } } }); try { return await deferred.promise; } finally { registration.unregister(); } }; super((resolve, reject) => observeCancellation().then(resolve, reject)); } } // delayWithCancellation function delayWithCancellation(timeoutMs, token) { console.log(`delayWithCancellation: ${timeoutMs}`); return new CancellablePromise((resolve, reject, setCancelListener) => { token.throwIfCancellationRequested(); const id = setTimeout(resolve, timeoutMs); setCancelListener(e => clearTimeout(id)); }, token); } // main async function main() { const tokenSource = new prex.CancellationTokenSource(); setTimeout(() => tokenSource.cancel(), 2000); // cancel after 1500ms const token = tokenSource.token; await delayWithCancellation(1000, token); console.log("successfully delayed."); // we should reach here await delayWithCancellation(1500, token); console.log("successfully delayed."); // we should not reach here } main().catch(error => console.log(error));