Skip to content

Instantly share code, notes, and snippets.

@hgl
Created July 30, 2015 02:46
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save hgl/fa6432904ddcf29ecafe to your computer and use it in GitHub Desktop.
Save hgl/fa6432904ddcf29ecafe to your computer and use it in GitHub Desktop.
Cancelable Promises

Background

In a promise system, there are two parties involved, an action initiator, and observers:

let done = fetch(url);
let insertDom = () => console.log("element inserted");
let read = () => done.then(insertDom);

in this example, fetch is the action initiator, read is an observer.

Cancelable Promises

I think what we really want from cancelable promises, is the ability to do two things:

  1. Abort the action.
  2. Let observers signal that they are no longer interested in the result of the action.

There seems to be some interests in exposing a cancel method in the promise object, where a observer could signal the action initiator that it should abort the action. This is wrong. ES2015 promises are currently one-way communication APIs. They are simple and easy to be reasoned about, and should be kept that way.

To achieve the first goal, I think the action initiator should have a separate API to abort the action, and when that happens, the returned promise should be rejected with a special error object. This means only when you have access to the action initiator, will you be able to abort the action.

For the second goal, promise objects should expose an API to undo the registering of callbacks done by the then method, much like what removeEventListener does to undo addEventListener in DOM. This means when an observer deregisters before the promise is resolved or rejected, its child promises are going to be in the pending state forever, unless it registers again.

Code Examples

Here are some code examples to illustrate the two points:

Abort

let query = queryDB(sql);
query.done // the promise object
query.abort() // abort

Signal Disinterest

let query = queryDB(sql);
let updateView = () => console.log("view updated");
let log = () => console.log("log view updated");
query.done.then(updateView).then(log); // register
query.done.ignore(updateView); // disregister, log will not be called
setTimeout(() => {
	query.done.then(updateView); // register again, log will be called.
}, timeEnoughForQueryToFinish);

The API names are debatable.

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