<p dir="ltr">What is cancelable is the value of the fetch() promise, not the fetch itself. Extending the promise API is extending the concept of control flow and I think this require a separated discussion. To make fetch() to be cancelable should not affect promises at all.</p>
<p dir="ltr">TL;DR; I think the cancelable promise makes no much sense. A promise is an abstraction for a control flow, it is not a value.</p>
<p dir="ltr">When you call a function f() returning a promise, f() is not returning a valid image* value. It is only returning an abstraction saying that, eventually, it will be "replaced" by the proper function or fail.</p>
<p dir="ltr">*image -> understood like in a mathematical context but allowing functions to have side effects.</p>
<p dir="ltr">This is why we can jump from promise-based syntax to await/async syntax. In the latter we are emulating the synchronous syntax in which there is only to flows, the regular flow and the exception flow. The exception flow, which is born from the need of checking runtime conditions that forces emergency paths.</p>
<p dir="ltr">With this scheme, there is no way for reacting upon abortion / cancellation unless you do something like:</p>
<p dir="ltr">try {<br>
  var response = await fetch(url);<br>
} ifAbort(reason) {<br>
  // what if aborted...<br>
}</p>
<p dir="ltr">This resembles a lot to a simple exception and so, there should be treated like another rejection error.</p>
<p dir="ltr">But this does not end here.</p>
<p dir="ltr">If we extend Promises API we are adding new flows, we are changing the flow definition. The need of a cancelable promise rising from fetch() is coupling fetch()'s specific implementation with control flow. This is why you ended with FetchPromise.</p>
<p dir="ltr">If you are going to allow fetch() to be cancelable, what I actually think is the thing which is indeed to be cancelable is the promise value for the fetch() returned promise.</p>
<p dir="ltr">All these members mentioned in the discussion such as .isCancelled, .requestCancel() and .setCancelHandler() should be part of the promise's value and not part of the promise itself.</p>
<p dir="ltr">var response = await fetch(); // it waits for the value of the promise which represents a fetch in progress.<br>
f.abort (); // this is what is abortable, not the flow itself.</p>
<p dir="ltr">Aborting the value will affect the way in which other members behaves and those are implementation details. For instance, a successfully abort() will cause .isAborted() to resolve in true and .json() to fail with an instance of FetchAborted() reason.</p>
<p dir="ltr">This way you are not coupling specific implementations' needs with control flow abstractions.</p>
<p dir="ltr">Notice that extending a flow abstraction is not bad at all but remember that If you continue pushing for the cancelable Promise, you are actually extending a control flow. So, IMHO, you should:</p>
<p dir="ltr">* Allow a third parameter for .then() to react upon the new flow path.<br>
* Change the Promise implementation to accept a second parameter which is the callback to be called when the flow is aborted.<br>
* Extend try syntax to take into account the new path to support await/async syntax**</p>
<p dir="ltr">**The need for an extension in try is another argument against. If you think carefully, an .abort() method is like controlling the flow from outside, in the await/async syntax is like controlling the "= await" part of the syntax which is simply unsupported.</p>
<p dir="ltr">var response = await fetch(url);</p>
<p dir="ltr">You can not abort() with await syntax from outside, it is only abortable by internal reasons. If it is only abortable by internal reasons, then it is almost the same than reject or accept. Just look at the value you are choosing for the abort result. If it is a valid response, you are accepting. If not, you are rejecting.</p>
<p dir="ltr">If you think with cancelable promises you're allowing richer execution models, think about Tasks as values of promises and use composition and not inheritance because they are not the same.</p>
<p dir="ltr">Hope it helps.</p>
<div class="gmail_quote">El 28/02/2015 05:01, "John Lenz" <<a href="mailto:concavelenz@gmail.com">concavelenz@gmail.com</a>> escribió:<br type="attribution"><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div dir="ltr"><br><div class="gmail_extra"><br><div class="gmail_quote">On Fri, Feb 27, 2015 at 7:49 PM, John Lenz <span dir="ltr"><<a href="mailto:concavelenz@gmail.com" target="_blank">concavelenz@gmail.com</a>></span> wrote:<br><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div dir="ltr">Closure Library's promise implementation supports "cancel":<div><br></div><div><a href="https://github.com/google/closure-library/blob/master/closure/goog/promise/promise.js#L502" target="_blank">https://github.com/google/closure-library/blob/master/closure/goog/promise/promise.js#L502</a><br></div><div><br></div><div>A promise is cancelled only if all the "child" promises are also cancelled.</div></div></blockquote><div><br></div><div>I did not say that correctly, a "parent" promise can be cancelled by a "child" it is the only child or all the children cancel.  A parent can alway cancel its children (to the children this is simply "reject").  It does add a significant amount of complexity to the promise implementation but it is for the most part contained there.</div><div><br></div><div>I don't believe that "cancel" can be added after the fact and an alternative (subclass or otherwise) is needed.</div><div> </div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div class="gmail_extra"><br><div class="gmail_quote"><span>On Thu, Feb 26, 2015 at 11:43 PM, Andrea Giammarchi <span dir="ltr"><<a href="mailto:andrea.giammarchi@gmail.com" target="_blank">andrea.giammarchi@gmail.com</a>></span> wrote:<br></span><div><div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div dir="ltr"><div>AFAIK bluebird did:</div><div><a href="https://github.com/petkaantonov/bluebird/blob/master/API.md#cancelerror-reason---promise" target="_blank">https://github.com/petkaantonov/bluebird/blob/master/API.md#cancelerror-reason---promise</a><br></div><div><br></div><div>But I agree once you've made Promises more complex than events ( xhr in this case ) nobody wins :-/</div><div><br></div><div>Although, specially for fetch or anything network related, there **must** be a way to bloody cancel that!</div><div><br></div><div>....right?</div><div><br></div></div><div><div><div class="gmail_extra"><br><div class="gmail_quote">On Fri, Feb 27, 2015 at 7:31 AM, Kevin Smith <span dir="ltr"><<a href="mailto:zenparsing@gmail.com" target="_blank">zenparsing@gmail.com</a>></span> wrote:<br><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><p dir="ltr">The discussion on that github issue surrounding promise subclassing makes my head spin, especially when it comes to working out how cancelation is supposed to flow through a graph of promise dependencies.  We should be wary of adding complexity to the core.</p>
<p dir="ltr">The simple way to view the situation is to say that promises are simply transparent containers for asynchronous values. Control capabilities should therefore be represented by a separate abstraction. This will help keep complexity at the edges. </p>
<p dir="ltr">Has any library experimented with the cancelation token approach yet? </p><div><div>
<div class="gmail_quote">On Feb 27, 2015 1:46 AM, "Anne van Kesteren" <<a href="mailto:annevk@annevk.nl" target="_blank">annevk@annevk.nl</a>> wrote:<br type="attribution"><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">As a heads up, there's some debate around the fetch() API how exactly<br>
request termination should work and how that affects promises:<br>
<br>
  <a href="https://github.com/slightlyoff/ServiceWorker/issues/625" target="_blank">https://github.com/slightlyoff/ServiceWorker/issues/625</a><br>
<br>
The WebRTC WG has also been discussing canceling in the context of<br>
terminating a request for permission from the user. I think they<br>
decided to postpone for now until there's a bit more progress on what<br>
cancelable promises means, but I would not expect everyone to wait<br>
forever.<br>
<br>
<br>
--<br>
<a href="https://annevankesteren.nl/" target="_blank">https://annevankesteren.nl/</a><br>
_______________________________________________<br>
es-discuss mailing list<br>
<a href="mailto:es-discuss@mozilla.org" target="_blank">es-discuss@mozilla.org</a><br>
<a href="https://mail.mozilla.org/listinfo/es-discuss" target="_blank">https://mail.mozilla.org/listinfo/es-discuss</a><br>
</blockquote></div>
</div></div><br>_______________________________________________<br>
es-discuss mailing list<br>
<a href="mailto:es-discuss@mozilla.org" target="_blank">es-discuss@mozilla.org</a><br>
<a href="https://mail.mozilla.org/listinfo/es-discuss" target="_blank">https://mail.mozilla.org/listinfo/es-discuss</a><br>
<br></blockquote></div><br></div>
</div></div><br>_______________________________________________<br>
es-discuss mailing list<br>
<a href="mailto:es-discuss@mozilla.org" target="_blank">es-discuss@mozilla.org</a><br>
<a href="https://mail.mozilla.org/listinfo/es-discuss" target="_blank">https://mail.mozilla.org/listinfo/es-discuss</a><br>
<br></blockquote></div></div></div><br></div>
</blockquote></div><br></div></div>
<br>_______________________________________________<br>
es-discuss mailing list<br>
<a href="mailto:es-discuss@mozilla.org">es-discuss@mozilla.org</a><br>
<a href="https://mail.mozilla.org/listinfo/es-discuss" target="_blank">https://mail.mozilla.org/listinfo/es-discuss</a><br>
<br></blockquote></div>