JavaScript Cancelable Promises Proposal
docs.google.com
docs.google.com
One key point is: since a promise can have multiple then-subscribers interested in it, (a) is it the subscriber's responsibility to signal disinterest (in which case the promise-creator needs to reference-count interest/disinterest)? Or (b) is it the promise-creator's responsibility to unilaterally cancel things, and the entire dependency tree must figure out how to fail elegantly? Either way, in a cancellation world, subscribers need to be rewritten either to (a) indicate disinterest, or (b) handle a cancellation coming from upstream, which is semantically distinct from an error.
Bluebird (whose designers seem to be involved in that thread) handles (a) pretty elegantly - it's subtle, but cancelablePromise.then() increments the reference count and returns a cancelablePromise that, when it or its descendants indicates disinterest, decrements the reference count: http://bluebirdjs.com/docs/api/cancellation.html
But I'm not quite convinced that this needs to be handled at the Promise spec level. If you're going to be adding "finally" clauses anyways, why not just use (b), special-case a type of "catch" and just not toast/console.error the exception if it was a CancellationError?
All this complexity, though, indicates the need for declarative data dependencies a la Relay or Meteor. Making the application programmer handle fetch/cancellation logic will be seen as an anti-pattern once those patterns reach maturity.
Think about an autocomplete search. Every additional letter should abort the prior ajax call and fire a new one. Right now I'm hammering my server because I want to use fetch().
The correct way to accomplish what you want is to either throttle or debounce your searching such that you reduce the amount of requests made in the first place.
1) because clients throttle connections. Suppose a user wants to navigate, you may need to be able to cancel in flight requests or the next page load might be significantly delayed.
2) file uploads can have potentially gigs of packets that haven't been sent yet, which you definitely need to be able to cancel.
If those can corrupt state then you're already at the complete mercy of the network... which is never a good idea regardless of whether this proposal is accepted or not.
Doing ad-hoc hacks around the lack of cancellation seems like a pretty big practical issue to me[1], so I'd certainly like to see something like this spec in the standard.
(Note: something like, not necessarily exactly this. I haven't thought about it deeply enough to be able to properly evaluate the spec.)
[1] Happens all the time when doing simple Ajax-on-futures where you really just want to ignore any result if the operation gets canceled in the UI before the response arrives.
function longTask() {
return new AbortablePromise((resolve, reject, onAbort) => {
const timer = setTimeout(resolve, 1000);
onAbort(reason => clearTimeout(timer));
});
}
const myTask = longTask
.aborted(reason => console.log('Aborted'))
.then(result => console.log('Done'))
.catch(reason => console.log('Error'));
setTimeout(() => myTask.abort('Changed my mind'), 300);
I did something similar with reporting progress: https://github.com/numtel/progress-promiseSo, I want progress reporting for promises too!