[whatwg] [Fetch] API changes to make stream depletion clearer/easier

Over in ServiceWorkerLand we've been getting stuck on the interaction
between methods that read a request/response body and the underlying stream.

The question was "Should methods that read the body consume it, meaning
nothing else can read it?"

https://github.com/slightlyoff/ServiceWorker/issues/372#issuecomment-51045111
http://jakearchibald.com/2014/reading-responses/

Both developers & those working on ServiceWorker were pretty split, but we
think the "consume" model is the right model, because:

* it doesn't regress on the memory usage of XHR (if responseType is json,
you can't get the original text)
* if you read the stream twice it'll fail, that may be surprising at first,
but it fails in your dev environment. If we need to buffer original data
for potential later rereads, you can get into memory issues and these will
likely show up on particular devices in production
* fits in well with streaming models

Fetch could change a bit to make this easier to understand & deal with:

* response.body should be removed until streams arrive
* The as* methods should be directly on the response, and named consumeAs*,
so response.consumeAsJSON()
* response.consumed (read-only) is true once the body stream has been
claimed by a reader
* response.clone() creates a clone of the response that can be consumed
independently, this is your opt-in to potential buffering
* Calling response.clone() on a consumed response creates another consumed
response
* If a body-reading method is given a response where response.consumed ==
true, it should throw/reject
* Any method that wishes to read the body of the response must cause
response.consumed to become true synchronously - we must be consistent with
this
* Methods that may read the body multiple times must still mark the
response as consumed. The clones they create are for internal use only
* postMessageing a response will cause it to be cloned, the original
remains unconsumed

The above is true for request too. So fetch(request) would synchronously
mark the request as consumed, even though fetch creates clones or tees
internally.

This allows developers to duplicate the stream if they need to and send one
response to the cache and another to the browser for rendering, you'll get
some buffering if one consumer is faster than the other. For the general
case of read-once, no buffering is required.

Received on Thursday, 21 August 2014 09:02:37 UTC