phuu is Tom Ashworth

Promise & fetch cancellation

25 Nov 2015

Working on fetch-engine has had me wondering about how we interact with the network from JavaScript.

I’d like the library to make network request timeouts simple. They’re a good practice for distributed systems, and we should all be using them without thinking about it.

To build timeout support, there needs to be a way cancel the in-flight request, free up HTTP resources in the browser, and notify the code performing the request that a timeout has occurred. To see how fetch-engine could do this, I looked into how we could make network requests.

fetch is becoming a standard and making its way into browsers, so my intuition was to base fetch-engine on it, hence the name.

As I was looking at the fetch API in more detail, I discovered that there isn’t a way to cancel an in-flight request. This makes timeouts impossible, which is a little unfortunate.

There’s a discussion about it at whatwg/fetch#27 but it’s an appalling exposition of the standards process, littered with personal attacks, pointed sarcasm, and useless noise. There was some constructive discussion, but no resolution.

There’s also a (thankfully shorter) es-discuss thread on Promise cancellation, but again without resolution.

The rest of this post conveys my thoughts on the issue. The world probably doesn’t need that, but here they are anyway. I’ll try to take an evidence based approach, and please call me out if I deviate from that.

Promises

First, what is a Promise? You should read the spec, but fundamentally they:

Promises have interface immutability, meaning their resolution cannot be interfered with, nor can the contained value be changed.

Promises are also simple, in that the full behaviour is described and understood easily.

These two properties have latent positive effects on large codebases, and are a good abstraction for a common set of tasks. That is why people like them, and why I think they’re great. Not perfect, but good-enough and useful.

Promise cancellation

When designing a new behaviour promise, these desirable properties should be maintained. For cancellation, that means:

A few in the the whatwg discussion felt the need to design a cancellation API. Pick your way through to find them. Unfortunately, the designs suffer variously from a couple of issues. They either:

None seem to ‘fit’, like a square peg in a round hole. Something’s not right.

Promise & fetch

Let’s look back at the key bits of a Promise. They:

Now compare that to the fetch spec. A fetch:

It seems to me that a Promise cannot be used as an interface for the intricacies of a fetch. It’s just more complicated than that.

So, here’s my opinion: cancellation does not fit within the Promise spec. It’s a simple, useful tool and it should stay that way.

Instead, let’s look hard at fetch, find new primitives that have desirable properties and the required features, and build the Fetch API around them.

Of course, Promises may be reused in places. That’s fine. That’s what abstractions are for.

What’s next?

I’m not going to design a solution here. Instead, I would like to see some things happen: