zenparsing / es-cancel-token

Cancel Tokens for ECMAScript
44 stars 1 forks source link

ECMAScript Cancel Tokens

Overview and Motivation

Asynchronous APIs frequently need to provide the user with some way to cancel long running or expensive operations. Some examples:

Userland promise libraries have addressed this need by adding a cancel method to promises. This proposal explores a different solution, inspired by the .NET task cancellation architecture.

Conceptually, a cancel token is created by the initiator of the asynchronous work. Cancellation may be requested at any time by the creator of the token. The cancel token is then passed as an argument to the function that starts the asynchronous operation. The receiver of the token can:

A primary feature of this design is that cancellation semantics are completely determined by the asynchronous operation that receives the token. There are no automatic or default cancellation effects.

The cancel token API is comprised of two new built-in constructors: CancelError and CancelToken.

CancelError

CancelError is a native error type used to indicate that an asynchronous operation has been cancelled.

CancelToken

The CancelToken constructor is a built-in constructor that creates and initializes a new CancelToken object.

new CancelToken ( executor )

Creates and initializes a new CancelToken object by calling executor with a function that, when called, requests cancellation.

// Create a token which requests cancellation when a button is clicked.
let token = new CancelToken(cancel => {
    $("#some-button").on("click", cancel);
});
// Create a token which requests cancellation when a promise is resolved
let token = new CancelToken(cancel => {
    somePromise.then(cancel);
});

get CancelToken.prototype.requested

Synchronously returns a Boolean value indicating whether cancellation has been requested for this token.

async function f(cancelToken) {
    await a();
    // Only execute `b` if task has not been cancelled.
    if (!cancelToken.requested)
        await b();
}

get CancelToken.prototype.promise

Returns a promise which will be resolved with a CancelError if cancellation has been requested for this token.

function delay(ms, cancelToken) {
    return new Promise((resolve, reject) => {
        // Register rejection if cancellation is requested.
        cancelToken.promise.then(reject);
        setTimeout(_=> resolve(), ms);
    });
}

CancelToken.prototype.throwIfRequested ( )

Synchronously throws a CancelError if cancellation has been requested for this token.

async function f(cancelToken) {
    await a();
    // Throw a CancelError upon cancellation
    cancelToken.throwIfRequested();
    await b();
}