
JavaScript Cancelable Promises Proposal - bpierre
https://docs.google.com/presentation/d/1V4vmC54gJkwAss1nfEt9ywc-QOVOfleRxD5qtpMpc8U/edit#slide=id.gc6f9e470d_0_0
======
b34r
Sorely needed, but the proposed implementation feels a little clunky. It's a
shame this functionality wasn't included from the get-go so modifying the
Promise architecture wasn't such a large consideration.

~~~
bricss
+1

------
btown
This thread has a much more in-depth discussion on the considerations for
designing this API:
[https://github.com/whatwg/fetch/issues/27](https://github.com/whatwg/fetch/issues/27)

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](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.

------
longlho
Not sure if this is needed. A Promise is basically an async representation of
a transaction where "cancel" can mean a slew of things. Even w/ `fetch`,
what's supposed to happen when you cancel? (connection abort? resource
modification reverse?) Cancel should just be a `rejection`, because the
Promise's purpose (update a remote resource) wasn't fulfilled

~~~
PhrosTT
Yes - fetch should abort. [https://developer.mozilla.org/en-
US/docs/Web/API/XMLHttpRequ...](https://developer.mozilla.org/en-
US/docs/Web/API/XMLHttpRequest/abort)

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().

~~~
dcherman
The request is already in flight, it's too late - you can't abort those
packets from getting to your server, you can only send new ones (which maybe
instruct the server to disregard your search or something).

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.

~~~
_jezell_
Doesn't matter that you can't cancel in flight packets:

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.

~~~
longlho
canceling GET is the simplest use case, XMLHttpRequest/fetch is already able
to abort. POST/PUT/DELETE, however, modifies remote resources which cannot be
easily "canceled" (it might corrupt server state and/or transaction might even
have to extend to client being able to fully "resolve" the Promise?)

~~~
lomnakkus
> POST/PUT/DELETE, however, modifies remote resources which cannot be easily
> "canceled" (it might corrupt server state and/or transaction might even have
> to extend to client being able to fully "resolve" the Promise?)

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.

~~~
longlho
yup, so why bloat up the spec? Introducing a 3rd option that represents a non-
deterministic remote state isn't entirely helpful IMO. Having the ability to
abort the connection should be enough (which is a rejection).

~~~
lomnakkus
Hm? My point was that the spec doesn't fundamentally change anything wrt. the
things you mentioned, so it should be evaluated on other merits (or lack
thereof).

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.

------
numtel
It's not that difficult to extend Promises. Show some code that's easy to
follow. If cancelled/canceled is too confusing, there are synonyms.

    
    
        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-
promise](https://github.com/numtel/progress-promise)

------
ColCh
We already have cancelable Promises in custom libs like bluebird, isn't?

So, I want progress reporting for promises too!

------
johnhenry
I'm intrigued. Any way to see an actual presentation?

------
bricss
Implementation shown in slides a bit dull

