This gist<https://gist.github.com/rbuckton/b69be537e41feec7fea7> contains the TypeScript declarations for the version of CancellationToken I’ve been using for a number of small projects. The basic API shape is:
```ts class CancellationTokenSource { constructor(linkedTokens?: CancellationToken[]); token: CancellationToken; cancel(reason?: any): void; close(): void; } class CancellationToken { static none: CancellationToken; canBeCanceled: boolean; canceled: boolean; reason: any; throwIfCanceled(reason?: any): void; register(callback: (reason?: any) => void): CancellationTokenRegistration; } interface CancellationTokenRegistration { unregister(): void; } ``` The approach I use has the following considerations: • The responsibility for cancellation is split between two types: o CancellationTokenSource – This type is responsible for propagating a cancellation signal and linking multiple tokens together (useful to cancel a graph of async operations, such as cancelling all pending fetch request). o CancellationToken – A read-only sink for a cancellation signal. Asynchronous operations can either synchronously observe whether the cancellation signal has been set, or register an callback for asynchronous notification of a cancellation signal. • Once a callback has been registered for asynchronous notification of a cancellation signal, it can later be unregistered. • Asynchronous notifications are queued and handled at a higher priority than Promise continuations. • The reason for cancellation can be explicitly supplied. If not supplied, the reason would be a generic “The operation was canceled” error. Splitting a cancellation signal across two classes has several benefits. One benefit is that it allows the producer of a cancellation signal to limit access to the ability to initiate that signal. This is important if you wish to have a single shared cancellation source for multiple concurrent asynchronous operations, but need to hand off a cancellation token to a third party without worrying that the third party code would unintentionally cancel operations that it does not itself own. Another benefit is the ability to create more complex cancellation graphs through linking multiple cancellation tokens. I agree with Domenic that it is necessary to be able to synchronously observe the canceled state of a cancellation token, and that it is also necessary to be able to observe a cancellation signal asynchronously. However, I have found that the asynchronous notification needs to be triggered at a higher priority than Promise “then” tasks. Consider the following, albeit contrived, example: ```js let source = new CancellationTokenSource(); let p = new Promise((resolve, reject) => { Promise.resolve(1).then(resolve); source.token.register(reject); source.cancel(); }); ``` Since “source.cancel()” is executed synchronously, one would expect that `p` would be rejected. If the notification were merely added to the same micro-task queue as Promise “then” tasks, `p` would be resolved first. By making the micro-task queue into a priority queue, we can allow cancellation notifications to be processed at a higher priority while still keeping the API itself asynchronous. In .NET, cancellation notifications are executed synchronously, however this conflicts with the intent to ensure an asynchronous API is consistently asynchronous. This approach also allows cancellation tokens to be more general-purpose. By not directly tying cancellation into Promises, they can be used with other future asynchronous primitives such as Observables, async generators, etc. Ron From: Kevin Smith<mailto:zenpars...@gmail.com> Sent: Monday, January 4, 2016 11:44 AM To: Tab Atkins Jr.<mailto:jackalm...@gmail.com>; Domenic Denicola<mailto:d...@domenic.me> Cc: es-discuss<mailto:es-discuss@mozilla.org> Subject: Re: Promises as Cancelation Tokens The best approach in cases like this is to avoid the word altogether. The fact that there's confusion at all means people will mess it up and get annoyed, even if there's a "winner" in overall usage. Hmmm... Maybe class CancelToken { constructor(init); get cancelRequested() : bool; whenCancelRequested(callback) : void; } Or more/overly tersely: class CancelToken { constructor(init); get requested() : bool; whenRequested(callback) : void; }
_______________________________________________ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss