Skip to content

Instantly share code, notes, and snippets.

@bripkens
Last active August 29, 2015 14:16
Show Gist options
  • Save bripkens/91e8a7b1f4880b6e80bd to your computer and use it in GitHub Desktop.
Save bripkens/91e8a7b1f4880b6e80bd to your computer and use it in GitHub Desktop.
Cancelable asynchronous operations with Promises

Lets take a look at existing cancelable AngularJS APIs:

$timeout

$timeout can be canceled via $timeout.cancel(promise). To make this possible, a $$timeoutId (source) is registered on the promise. This value is read by the $timeout.cancel(promise) function to actually call clearTimeout(...).

Unfortunately, this is not a good example for cancelable asynchronous operations with Promises.

$timeout returns a promise on which the then(onFulfilled, onRejected) function can be called. This function returns a new promise which does not have a $$timeoutId property and therefore cannot be used to call $timeout.cancel(promise).

This means that $timeout cannot be considered a good example for idiomatic cancelabel asynchronous operations because the transformation of promises' values via then(onFulfilled, onRejected) is probably the most common Promise interaction pattern. An API which fails to work in the majority of cases is probably not a good API.

This does not mean that the $timeout API is generally broken or bad for that matter. The $timeout API just does not match our requirement. Quite the contrary: $timeout is a nice example of a translation of standard language features to framework specific code. This results in familiar looking code for developers who are used to the setTimeout and clearTimeout functions.

var timeoutHandle = $timeout(...);
$timeout.cancel(timeoutHandle);

var timeoutHandle = setTimeout(...);
clearTimeout(timeoutHandle);

Requirements for a good API

So what could a nice API look like? First of, we need to establish a common understanding:

What should be cancelled?

One probably does not want to cancel the eventual result, i.e. the promise. Not matter what happens, one always wants to know what happens with an asynchronous operation. What one probably wants to do is to cancel the asynchronous operation which settles the promise. Additionally, from a semantic point of view, one mostly does not want to cancel because one does not want a result, but because one needs to cancel because of resource constraints, user instructions, errors or for other reasons.

This has some implications: An API that enables canceling is not concerned with promises as promises only model the result! The API should cancel the operation and as such users of the API need to be able to differentiate between operation and result.

Luckily, there is at least one example of such an API design in the AngularJS world: Angular UI bootstrap modals!

var {result, close} = $modal.open(...);
// yay, result is a Promise and close is a our cancel counterpart :)

Okay, I need to start working now and don't have more time to dive into this right now. I will probably write a blog post about this topic :)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment