Clear Approach to Cancellation of Asynchronous Operations
This resource discusses the concept of cancellation primitives, providing a clear and consistent approach to cancelling asynchronous operations. It emphasizes separating the source and sink, enabling synchronous and asynchronous observation of cancellation requests. The goal is to facilitate composable non-trivial cancellation graphs. It covers observability, source/sink dynamics, parent/child aggregation, and current proposals like Promise as a token. The article also delves into using existing APIs, asynchronous observation, and closure persistence issues.
Download Presentation
Please find below an Image/Link to download the presentation.
The content on the website is provided AS IS for your information and personal use only. It may not be sold, licensed, or shared on other websites without obtaining consent from the author. Download presentation by click this link. If you encounter any issues during the download, it is possible that the publisher has removed the file from their server.
E N D
Presentation Transcript
CANCELLATION PRIMITIVES Ron Buckton - Microsoft Corporation
Clear and consistent approach to the cancellation of asynchronous operations General purpose coordination primitive Host API integration (fetch, module loading, etc.) MOTIVATIONS
Separation of source and sink Cancellation request can be observed synchronously, via property Cancellation request can be observed asynchronously, via callback Able to unregister callbacks Composable for non-trivial cancellation graphs GOALS
Source Owned by caller Sink Received by callee Can observe cancellation state Can share entangled Sink with multiple callees Cannot initiate cancellation signal on Source Initiates cancellation signal Callee A cannot interfere with Callee B using the same Sink SOURCE/SINK
Synchronous Observe cancellation request via property Asynchronous Observe cancellation request via callback Able to unregister/unsubscribe from cancellation Useful for loops and multi-phase operations in async functions Allows GC of closures Game Loops Stop listening when callback is no longer needed Best for non-async functions that return Promise Async Iteration Best for async functions OBSERVABILITY
Parent/Child Aggregation Source1 Child1 Source2 Aggregate Root Child2 Source3 Child3 COMPOSABLE
Promise as Token AbortController (WHATWG) CancellationToken (TC39) CURRENT PROPOSALS
function asyncfn(token) { token.then(() => { /*cancelled*/ }); } let cancel, token = new Promise(resolve => cancel = resolve); asyncfn(token); cancel(); PROMISE AS TOKEN
Uses existing API Cannot be observed synchronously Can be observed asynchronously Cannot be unregistered Must use additional logic to prevent execution Closure persists for lifetime of source Not easily composable PROMISE AS TOKEN
function asyncfn(signal) { const onabort = () => { /*cancelled*/ }; signal.addEventListener('abort', onabort); signal.removeEventListener('abort', onabort); if (signal.aborted) { /*cancelled */ } } const controller = new AbortController(); asyncfn(controller.signal); controller.abort(); ABORTCONTROLLER (WHATWG)
New API: https://github.com/whatwg/dom/pull/437 Can be observed synchronously Can be observed asynchronously Takes dependency on DOM events Callbacks can be removed (via removeEventListener) ABORTCONTROLLER (WHATWG)
function asyncfn(token) { const reg = token.register(() => { /*cancelled*/ }); reg.unregister(); if (token.cancellationRequested) { /*cancelled*/ } } const source = new CancellationTokenSource(); asyncfn(source.token); source.cancel(); CANCELLATIONTOKEN
New API: https://github.com/tc39/proposal-cancellation Can be observed synchronously Can be observed asynchronously Callbacks can be removed (via unregister) Easily composable: async function asyncfn(token1, token2) { const source = new CancellationTokenSource([token1, token2]); setTimeout(() => source.cancel(), 500); await otherfn(source.token); } CANCELLATIONTOKEN
CancellationTokenSource new CancellationTokenSource([linkedTokens]) source.token source.cancel() source.close() CANCELLATIONTOKEN API
CancellationToken CancellationToken.none CancellationToken.canceled token.cancellationRequested token.canBeCanceled token.throwIfCancellationRequested() token.register(callback) registration.unregister() CANCELLATIONTOKEN API
Promise new Promise(executor, token) promise.then(onfulfill, onreject, token) Observable observable.subscribe(observer, token) Dynamic import import( module , token) POSSIBLE FUTURE INTEROP
Stage 0 Identified Champions: Ron Buckton, Brian Terlson Strawman available https://github.com/tc39/proposal-cancellation Early Spec Proposal available https://tc39.github.io/proposal-cancellation/ Prototype available https://github.com/rbuckton/prex Requesting Stage 1 STATUS