├── .gitignore └── README.md /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | _* 3 | node_modules 4 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ## ECMAScript Cancel Tokens 2 | 3 | ### Overview and Motivation 4 | 5 | Asynchronous APIs frequently need to provide the user with some way to cancel long running or expensive operations. Some examples: 6 | 7 | - A browser HTTP fetch API needs to allow the user to cancel network operations if the current request is no longer required by the user interface. 8 | - A database access API needs to allow the user to cancel a long-running query when the client no longer needs the results of that query. 9 | - A promise-based Observable implementation (where the subscription method returns a promise) needs to allow the user to cancel the subscription. 10 | 11 | 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](https://msdn.microsoft.com/en-us/library/dd997396.aspx). 12 | 13 | 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: 14 | 15 | - Synchronously check at any time for a cancellation request. 16 | - Synchronously throw an error if cancellation has been requested. 17 | - Register a callback that will be executed if cancellation is requested. 18 | - Pass the *cancel token* to subtasks if it chooses to do so. 19 | 20 | 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. 21 | 22 | The cancel token API is comprised of two new built-in constructors: *CancelError* and *CancelToken*. 23 | 24 | ### CancelError 25 | 26 | *CancelError* is a native error type used to indicate that an asynchronous operation has been cancelled. 27 | 28 | ### CancelToken 29 | 30 | The *CancelToken* constructor is a built-in constructor that creates and initializes a new *CancelToken* object. 31 | 32 | #### new CancelToken ( _executor_ ) 33 | 34 | Creates and initializes a new *CancelToken* object by calling _executor_ with a function that, when called, requests cancellation. 35 | 36 | ```js 37 | // Create a token which requests cancellation when a button is clicked. 38 | let token = new CancelToken(cancel => { 39 | $("#some-button").on("click", cancel); 40 | }); 41 | ``` 42 | 43 | ```js 44 | // Create a token which requests cancellation when a promise is resolved 45 | let token = new CancelToken(cancel => { 46 | somePromise.then(cancel); 47 | }); 48 | ``` 49 | 50 | #### get CancelToken.prototype.requested 51 | 52 | Synchronously returns a Boolean value indicating whether cancellation has been requested for this token. 53 | 54 | ```js 55 | async function f(cancelToken) { 56 | await a(); 57 | // Only execute `b` if task has not been cancelled. 58 | if (!cancelToken.requested) 59 | await b(); 60 | } 61 | ``` 62 | 63 | #### get CancelToken.prototype.promise 64 | 65 | Returns a promise which will be resolved with a *CancelError* if cancellation has been requested for this token. 66 | 67 | ```js 68 | function delay(ms, cancelToken) { 69 | return new Promise((resolve, reject) => { 70 | // Register rejection if cancellation is requested. 71 | cancelToken.promise.then(reject); 72 | setTimeout(_=> resolve(), ms); 73 | }); 74 | } 75 | ``` 76 | 77 | #### CancelToken.prototype.throwIfRequested ( ) 78 | 79 | Synchronously throws a *CancelError* if cancellation has been requested for this token. 80 | 81 | ```js 82 | async function f(cancelToken) { 83 | await a(); 84 | // Throw a CancelError upon cancellation 85 | cancelToken.throwIfRequested(); 86 | await b(); 87 | } 88 | ``` 89 | --------------------------------------------------------------------------------