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 <[email protected]> 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 <[email protected]> > 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 <[email protected]> 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: >> https://github.com/promises-aplus/cancellation-spec/issues/16. >> >> what do you think about it? >> >> 2015年8月3日(月) 8:43 Glen Huang <[email protected]>: >> >>> 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 >>> [email protected] >>> https://mail.mozilla.org/listinfo/es-discuss >>> >> >> _______________________________________________ >> es-discuss mailing list >> [email protected] >> https://mail.mozilla.org/listinfo/es-discuss >> >> > >
_______________________________________________ es-discuss mailing list [email protected] https://mail.mozilla.org/listinfo/es-discuss

