Cancelable promises proposal

Andrea Giammarchi andrea.giammarchi at
Tue Aug 4 05:32:41 UTC 2015

my proposal doesn't make abortability accidental, only promises that has
passed through their initialization the callback would be cancelable,and
this could be reflected through a `.cancelable` property. We could have
 `.abort()` throwing if used when cancelable is true ( or not
undefined for backward compatiblity sake )

The only problem I see with my proposal is thay purists would  never accept
cancel-ability in first place, and pragmatists would never find out what
should be the behavior once aborted 'cause Promise can only reject and
never be ignored.

So the TL;DR is that I don't see cancel-able promises becoming reality at
any point in these days, I rather would think from scratch something better
( Task ? ) and leave Promises the way these are,  hoping standard bodies
will just stop putting/using them for everything asynchronous that might
take more than 10ms and **should** be cancelable.

I'm the first one that want them  cancelable, and at this point, after
months of discussions, the one that also doesn't see that as a solution.

Best Regards

On Tue, Aug 4, 2015 at 1:27 AM, Glen Huang <curvedmark at> wrote:

> @Andrea @Yad
> The only thing I'm not sure about is this "some promises have the abort
> ability, some don't" design. It might seem clear when you first create that
> promise, but it gets messy when you start to pass that promise around. It's
> very easy for some function to accidentally have the ability to abort()
> where it shouldn't.
> On Aug 4, 2015, at 1:19 AM, Andrea Giammarchi <andrea.giammarchi at>
> wrote:
> not so different from what I've proposed already, except it looks ugly
> with a `self` at the end, and it's based on runtime method attachment that
> could happen at any time or mislead, or forget to invoke reject etc etc ...
> I will try to stay away from this thread 'cause I've already talked as much
> as I could about this topic but my proposal was this one:
> ```js
> var p = new Proomise((resolve, reject, fnIfAborted) => {
>   let timer = setTimeout(resolve, 3000, 'All Good');
>   // **only** if fnIfAborted is invoked here
>   // the promise will be cancelable, otherwise it cannot
>   // be cancelable later on, and it's not possible
>   // to even invoke fnIfAborted later on or asynchronously
>   // this is the best I could think  to make the contract as simple as
> possible
>   fnIfAborted(function () {
>     clearTimeout(timer);
>   });
> });
> ```
> Once established that the user that created the Promise is the only one
> capable of deciding if that could be cancelable or not, there's no way
> anything else could interfeer with that cancelability, and the promise can
>  be passed around as cancelable, or simply wrapped through another non
> cancelable promise.
> This gives the promise creator the ability to cancel it without exposing
> such ability to the outer world.
> The eventual `p.abort()` if executed after the promise has been
> resolved/rejected will **not** invoke the `fnIfAborted` internally passed
> callback.
> Reasons such callback must be defined in the Promise scope is because only
> there there would be eventually the ability to resolve, reject, or abort
> the operation.
> It's simple, it's probably a bit ugly, but it's there to solve edge cases
> ( basically all network related cases or every case that might take long
> time and the user, or even  the developer, might get border and would like
> to do something else instead of wasting resources )
> Best Regards
> On Mon, Aug 3, 2015 at 7:08 AM, Yad Smood <y.s.inside at> wrote:
>> I have thought about something similar before, and used it in one of my
>> libs. Recently, I have come up another idea, it was already implemented on
>> Yaku:
>> let Promise = require('yaku')
>> // The `self` is the instance of the newly created promise.let p = new Promise((resolve, reject, self) => {
>>     let tmr = setTimeout(resolve, 3000)
>>     let self.abort = () => {
>>         clearTimeout(tmr)
>>         reject(new Error('abort promise'))
>>     }
>> })
>> p.abort()
>> The origin post is here:
>> what do you think about it?
>> 2015年8月3日(月) 8:43 Glen Huang <curvedmark at>:
>>> I was discussing with Jake Archibald about cancelable promises the other
>>> day. I was trying to convince him promise.cancel() might not be a good
>>> idea. But that conversation unfortunately leans more towards on how the
>>> abort API should be exposed on fetch. I did provide some thoughts on that
>>> topic, and think the abort API represents a strong use case for cancelable
>>> promises. But I feel what's more important is the underlying control flow
>>> design.
>>> So I would like to offer my proposal of cancelable promises here, and
>>> would like to ask if you think it's a good idea, or if promise.cancel() is
>>> actually a good idea and my understanding of promises is flawed.
>>> I think that promises should be an observation API. In other words, it
>>> should be kept as one-way communication. This keeps promises simple and
>>> easy to reason about.
>>> When we talk about cancelable promises, what we really want is the
>>> ability to:
>>> 1. abort the action that the root promise observes.
>>> 2. let child promises show disinterest on the result of that action
>>> With the premise that promises should be one-way communication, it's
>>> clear that #1 should be achieved with a separate API. For example:
>>> ```
>>> let query = queryDB(sql);
>>> query.done.then(data => console.log(data));
>>> query.abort();
>>> ```
>>> This means you need to have access to that separate API in order to
>>> abort the action, instead of just the promise.
>>> And abort() rejects the root promise with a special error object, if
>>> it's pending.
>>> This also means the abort API doesn't have to be universal. Each action
>>> initiator can design their own APIs to abort that action.
>>> And correspondingly, to create a "cancelable promise" with the Promise
>>> constructor, it can be as simple as:
>>> ```
>>> function doAction() {
>>>         let abort;
>>>         let done = new Promise((res, rej) => {
>>>                 asyncAction(res, rej);
>>>                 abort = () => rej(new AbortError());
>>>         });
>>>         return {done, abort};
>>> }
>>> ```
>>> For #2, I propose we add a method to Promise.prototype that undos
>>> .then() (probably also a sugar to undo .catch()) like removeEventListener
>>> undos addEventListener. For example.
>>> ```
>>> let query = queryDB(sql);
>>> let updateView = data => render(data);
>>> let log = data => console.log(data);
>>> query.done.then(updateView).then(log);
>>> query.done.ignore(updateView); // deregister callback, updateView and
>>> log will never be called
>>> setTimeout(() => {
>>>         query.done.then(updateView); // unless callback is registered
>>> again
>>> }, timeEnoughForQueryToFinish);
>>> ```
>>> You can think it as that each promise keeps a list of its child
>>> promises, when the same callback is passed to .ignore() it sets a flag on
>>> the corresponding child promise so that when itself resolves/rejects, it
>>> won't pass that state to that child promise, unless that the same callback
>>> is later registered again.
>>> What do you think of this design? Do you think it covers all of your use
>>> cases for cancelable promises?
>>> I have to give credit for Kyle Simpson and Jake Archibald for this idea.
>>> Kyle's opposition of sending signal back to the promise vendor, and Jake's
>>> argument that we need a way to let an observer signal disinterest greatly
>>> clarifies my understanding of promises.
>>> I guess someone has probably expressed this idea somewhere in some way
>>> (or in some libraries). Sorry if I missed that.
>>> _______________________________________________
>>> es-discuss mailing list
>>> es-discuss at
>> _______________________________________________
>> es-discuss mailing list
>> es-discuss at
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <>

More information about the es-discuss mailing list