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

We're currently looking into two solutions: Cancellable tokens and cancellable promises. I'm going by the following requirements:

* Promises should have `.finally(func)`, along with `.then(onfullfill, onreject, onfinally)` to mirror the sync counterpart
* If a promise has settled before cancellation, cancellation is a no-op
* A cancelled promise will not call `onfullfill` or `onreject`, but will call `onfinally`
* Cancellation should ideally be chain aware (having to manually pass a token to each call isn't a great API)
* If cancellation happens after a promise has started work, but hasn't yet resolved, it should be able to react to this via a callback that can easily cancel the underlying operation(s)
* A parent promise should be able to react if all its children have cancelled
* It should be easy for a promise receiver to signal disinterest/cancellation (such as `event.respondWith` in a service worker)
* It should be easy to vend a promise that cannot be cancelled by the receiver

Have I missed anything?

I'm still a fan of the ref-counting approach, but it creates a tricky situation and I'm open to suggestions… Take the following nonsensical example:

```js
var fetchPromise = fetch(url);
var jsonPromise = fetchPromise.then(r => r.json());
var fetchPromise2 = fetch(url2);
var waitingPromise = fetchPromise2.then(_ => fetchPromise);
// Ref counts
// fetchPromise:   2
// jsonPromise:    0
// waitingPromise: 0
```

Imagine `fetchPromise` has yet to settle, `fetchPromise2` has fulfilled with a `Response`, `waitingPromise` has resolved with `fetchPromise`. Then:

```js
waitingPromise.cancel();
```

1. `waitingPromise` cannot be marked for cancelation as it has resolved. But since it hasn't settled, its resolved value, `fetchPromise` has its ref count decreased by 1, to 1.

And there's the problem. Although `.cancel` was called on this unsettled promise, it continues to resolve with `fetchPromise`.

This wouldn't be a problem with:

```js
var fetchPromise = fetch(url);
var jsonPromise = fetchPromise.then(r.clone() => r.json());
var fetchPromise2 = fetch(url2);
var waitingPromise = fetchPromise2.then(_ => fetchPromise).then();
// Ref counts
// fetchPromise:   2
// jsonPromise:    0
// waitingPromise: 0
```

…as `waitingPromise` hasn't resolved due to the added `.then()`. I think we either need to find a way to do something like that in the spec (maybe it does already?), or allow a resolved but unsettled promise to cancel. Both of these would also help if a `CancelablePromise` resolved with a foreign thenable.

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

Received on Tuesday, 14 April 2015 15:58:16 UTC