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

The controller approach is certainly the quickest way we'll solve this, but it's pretty ugly, I'd like to treat it as a last resort & try for the cancellable promises approach.

# Cancellation based on ref-counting

I'm still a fan of the ref counting approach, and from the thread on [es-discuss](https://esdiscuss.org/topic/cancelable-promises) it seems that libraries take a similar approach.

```js
var rootFetchP = fetch(url).then(r => r.json());

var childFetchP1 = rootFetchP.then(data => fetch(data[0]));
var childFetchP2 = rootFetchP.then(data => fetch(data[1]));
var childP = Promise.resolve(rootFetchP).then(r => r.text());

childFetchP1.abort();
// …aborts fetch(data[0]), or waits until it hits that point in the chain, then aborts.
// fetch(url) continues

childFetchP2.abort();
// …aborts fetch(data[1]), or waits until it hits that point in the chain, then aborts.
// fetch(url) aborts also, if not already complete. Out of refs.
// childP hangs as a result

rootFetchP.then(data => console.log(data));
// …would hang because the fetch has aborted (unless it completed before abortion)
```

Cancelling a promise would cancel all its child CancellablePromises.

# Observing cancellation

If a promise is cancelled, it needs to be observable down the chain, at least by other cancellable promises. Yes, you don't want to do the same as "catch", but you often want to do "finally", as in stop UI such as spinners. Say we had:

```js
var cancellablePromise = new CancellablePromise(function(resolve, reject) {

}, function onCancel() {
  // Called when this promise is explicitly cancelled, or when all child cancellable promises are cancelled.
  // Only called if promise was pending
});

// as a shortcut:
CancellablePromise.resolve().then(onResolve, onReject, onCancel)
// …attaches the onCancel callback to the returned promise
```

# Usage in fetch

Fetch would return a CancellablePromise that onCancel would terminate the request. The stream reading methods `response.text()` etc would return their own CancellablePromise that would terminate the stream.

If you're doing your own stream work, you're in charge, and should return your own CancellablePromise:

```js
var p = fetch(url).then(r => r.json());
p.abort(); // cancels either the stream, or the request, or neither (depending on which is in progress)

var p2 = fetch(url).then(response => {
  return new CancellablePromise(resolve => {
    drainStream(
      response.body.pipeThrough(new StreamingDOMDecoder())
    ).then(resolve);
  }, _ => response.body.cancel()});
});
```

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

Received on Thursday, 26 March 2015 12:19:21 UTC