you-are-cancelled

An implementation of the cooperative cancellation model that is heavily inspired by the .NET implementation.

Usage no npm install needed!

<script type="module">
  import youAreCancelled from 'https://cdn.skypack.dev/you-are-cancelled';
</script>

README

You Are Cancelled

Available from NPM Built using Travis

An implementation of the cooperative cancellation model that is heavily inspired by the .NET implementation.

Usage

The TL;DR is that there are Cancellation Token Sources where each have a Cancellation Token associated with them. An operation that can be cancelled and spawns one or more async sub-operations would create a Cancellation Token Source and give said sub-operations the resulting Cancellation Token. When interrupted, the operation will request a cancellation using the aforementioned Cancellation Token Source, the associated token will then communicate that cancellation request to all sub-operations allowing them to gracefully abort.

This module can be treated as an ES module:

import * as youAreCancelled from 'you-are-cancelled';
// or
import { CancellationTokenSource } from 'you-are-cancelled';

This module can also be treated as a CommonJS module:

const youAreCancelled = require('you-are-cancelled');
// or
const { CancellationTokenSource } = require('you-are-cancelled');

Cancellation Token Sources

An operation that can be cancelled and spawns one or more asynchronous sub-operations would create the Cancellation Token Source:

const source = new CancellationTokenSource();

When the operation needs to be cancelled, you can request a cancellation:

setTimeout(function ()
{
  source.cancel('Cancelling operation because it took longer than 5 seconds.');

}, 5000);

Cancellation Tokens

The cancellation token is responsible for propagating the cancellation requested by its associative Cancellation Token Source. Every Cancellation Token Source has a unique token associated with it. You will give this token to any asynchronous operation that can be cancelled:

await getRecordsFromDatabase(source.token);

Important: Do not pass around the Cancellation Token Source!

Reacting to cancellation requests

You can register a callback that will execute when a cancellation has been requested:

token.register(function (error)
{
  // Clean up...
});

Important: If a cancellation has already been requested, the callback will be executed immediately.

Handling cancellation requests

The cancellation token is also a thenable object, so you can race it against other promises:

try
{
  await Promise.race([operation, token]);
}
catch (error)
{
  if (error instanceof OperationCancellationError)
  {
    // Was cancelled. Could do some clean up here.
  }
  else
  {
    // Operation error.
  }
}

The cancellation token will never resolve; it will only ever be pending or rejected. When a cancellation is requested, the token is rejected with an OperationCancellationError with a message that matches the reason provided during the said cancellation request.

Furthermore, you can throw an OperationCancellationError if a cancellation has already been requested:

token.throwIfCancellationRequested();

The Dummy Cancellation Token

When defining an operation that can be cancelled, it is good practice to make the cancellation token optional. The CancellationToken.None dummy token can help you with this - you can use it as a default parameter value so your code can always assume it has a cancellation token to work with:

async function getRecordsFromDatabase(filter, token = CancellationToken.None)
{
  // ...
}

The token state

Each cancellation token has the following state associated with it:

Flag Description
canBeCancelled Indicates whether the token is capable of being in a cancelled state. Normally this will be true, but for the CancellationToken.None dummy token this will always be false.
isCancellationRequested Indicates whether a cancellation has been requested. For the CancellationToken.None dummy token this will always be false.

Getting started

This module is available through the Node Package Manager (NPM):

npm install you-are-cancelled

Development

Building

You can build UMD and ESM versions of this module that are minified:

npm run build

Testing

This module also has a robust test suite:

npm test

This includes a code quality check using ESLint. Please refer to the .eslintrc files to familiar yourself with the rules.

License

This project is released under the MIT license.