[streams] Should readable streams start right away? (#269)

Inspired by https://github.com/slightlyoff/ServiceWorker/issues/606, it occurs to me that this might be a more general problem.

Right now, creating a readable stream is intended to start the flow of data into it. At least one chunk should be enqueued, to move the stream from `"waiting"` to `"readable"`. If this does not happen, then the stream never becomes readable, and is useless. In terms of the API, this manifests in how constructing the stream kicks off a call to the underlying source's `start()`, and then if `start()` succeeds we immediately call `pull()`.

However, there's another argument, which is that we want readable streams to be able to "represent" resources like HTTP request bodies or files. And in this case, it's often advantageous to have an "inert" request body or file object, which hasn't started doing any I/O (or at least hasn't done the "last mile" of I/O, e.g. IPC to move the chunks into the JS thread's process), until you ask it to.

In https://github.com/slightlyoff/ServiceWorker/issues/606 the current design seems to be guiding us toward the `Request` object being the "inert" request body, with `req.stream()` being a method that says "reify this into a JS-visible stream by doing IPC to get the chunks into the appropriate process." In that thread I phrased the two mental models as:

- "Requests have a body which is a stream, plus convenience methods like .text() for reading the stream." vs.
- "Requests are opaque objects which don't necessarily have an associated body. You can call `.stream()` to reify the body as a stream, or `.text()` to reify the body as text, etc."

You could also imagine a similar situation for files, where e.g. `const file = fs.getFile("file.flac")` gives you an opaque file object without doing any I/O, allowing e.g. `file.moveTo("/tmp")` but then also `file.stream()` to start reifying the data as a stream. (This is *not* how Node.js's `fs` API works, for the record.)

I see a few paths forward on this:

1. Keep the current design. APIs that need the separation discussed here will need to manually stratify themselves into opaque objects with stream-vending methods, as appropriate---e.g. the `req.stream()` pattern.
2. Don't have streams start immediately upon creation. Maybe by adding some kind of `rs.start()` method (eww), or by making `rs.ready` start the flow (not great either)?
3. Move to async read. (Perhaps also motivated by #253?) Then the first call to `read()` is a signal to start the flow of data, and the stream could avoid starting until that happens.

I am leaning toward just keeping the current design, but I wanted to bring it up.

---
Reply to this email directly or view it on GitHub:
https://github.com/whatwg/streams/issues/269

Received on Wednesday, 21 January 2015 17:49:02 UTC