Re: [fetch] Aborting a fetch (#27)

@zowers 
> Abort semantics are needed because browsers have limited amount of connections to the server, so if connections remain open after cancel() declares disinterest, and there could be situation when connection limit is reached

Disinterest semantics are capable of dealing with this just fine as they do in other systems. Abort semantics are highly discouraged everywhere to the point a lot of higher level systems deprecated or removed them altogether from user-level code. Aborting a promise (or observable, or task, or whatever) parallels to a thread abort. It's very dangerous and very abusable. It's giving users a footgun. 

@jan-ivar 
> There's also lots of time-math, scheduling and utility functions one can do and make that build on promises without taking a direct interest in their result (e.g. Promise.all or the queue(() => {})

Uhh.. consuming a promise is clearly a way to signal a direct interest in its results. This is a case where users would be bitten by not having sound disinterest semantics.

Your `.catch(() => {})` example is a real use case though - typically in order to suppress unhandled rejections or to suppress errors explicitly. This of course can be dealt with either by calling `.cancel` on that promise immediately or creating a method that suppresses rejections without interfering with cancellation. In bluebird we call it [`suppressUnhandledRejections`](http://bluebirdjs.com/docs/api/suppressunhandledrejections.html) and it solves that semi-problematic use case you speak of explicitly.

I ask you to reconsider what semantics we'd like to give users - giving them cancellation with abort semantics is exactly the "action at a distance" you speak of. Giving them disinterest semantics covers every practical use case without letting them perform an action at a distance - all they can do is signal disinterest and the producer gets to do what they want with it. 

@appden 
> I'm now assuming I would need to call cancel() on both responsePromise and resultPromise?

Nope, just because you created another reference to a promise does not mean you've created another promise. You would only have to cancel the very last promise and all intermediate results would propagate the disinterest. It's much easier to stomach than you'd imagine. I encourage you to experiment with bluebird and see how simple the semantics are for yourself.

> ...without retaining references to all the intermediate promises and calling cancel() on them? The system can't really know if my parseResponse function is operating as a transformer on the response, or a handler that actually uses the response to, for instance, update the UI on my site.

Note _explicit_ cancellation would still cancel it (and not execute the `then` handler), this is not the same as garbage collection. So calling `.cancel` would do what you'd expect it to.

@riking 
> Some of that example code looks dubious. Wouldn't you have to do this? For a long-polling usecase:

No, that code is "write once", you'd write a combinator for doing it once and lifting a promise returning function to only care about the last result (like Rx has flatMapLatest) and then call it whenever you want the result. 

@eplawless 
> @riking Yes, you would. That's the problem with Promise semantics for this use case.

Sorry but from what I understand that's not the reason @blesh is advocating for tasks and observables here at all. Please don't put words in his mouth. The difference between promises and observables _for this use case_ is that promises proxy results and RxJS observables parallel functions and not their results. That's why you can write `.flatMapLatest` on an RxJS observable but with Promises or another value primitive you'd need to call flatMapLatest on the _function_ returning the promise. 

See the related interesting discussion [here](https://github.com/zenparsing/es-observable/issues/11). You can read more about [multicast and unicast](https://github.com/zenparsing/es-observable/issues/66) here and of course on https://github.com/kriskowal/gtor. 

Anyway, you can read my response to @appden above. The only difference between promises and observables in this regard is that the most popular observable library ships with this built in and the most popular promise library (assuming: native promises) does not.

@appden 
> I assume that if a fetch is cancelled before it resolves, the catch() handlers would run.

No, that does not settle with disinterest semantics. Promise cancellation is like a generator's `return` called on the generator. It runs `finally` blocks but not catch handlers. Catch handlers running implies abort semantics which is really dangerous. Again, this is something I encourage you to experiment with with bluebird promises - I'm confident after a few tries you'll see just how intuitive and sound it is. 

---
Reply to this email directly or view it on GitHub:
https://github.com/whatwg/fetch/issues/27#issuecomment-177167833

Received on Saturday, 30 January 2016 12:48:29 UTC