[streams] Change the model for ReadableStream to have async read() (#296)

This replaces the dual ready + read() approach previously, which was derived from the epoll(7) + read(2) paradigm. In #253 we did a deep dive on real-world implementation strategies for byte streams, and discovered that the ready + read() model causes a conflict with the semantics we want for byte streams. Briefly, because some byte streams will demand to know the size of the buffer they must fill before doing any I/O (the fread(3) model), the byte stream method that reads into a given typed array must be asynchronous. If such byte streams are then to conform to the readable stream interface, with a no-argument read() method that is an auto-allocating version of the read-into method, then read() must also be async, across all readable streams.

This is a usability upgrade for consumers, in many cases. However, for non-byte streams, it potentially costs more microtasks when multiple chunks of data would be available synchronously. We are hopeful that even if current JS engine microtask queues are not as fast as they could be, they will improve over time until this overhead is negligible (which in theory it should be).

Alongside this change, we moved the read() method from the readable stream to the reader (now called "readable stream reader" instead of "exclusive stream reader"). This drastically simplifies the stream/reader interaction, and also allows the possibility of different types of readers which have different reading behavior---again, very helpful for byte streams. The usability impact is also positive, as it guides consumers toward using piping instead of directly reading chunks from the stream.

Note that read() promises fulfill with { value, done } instead of using an EOS sentinel value. This avoids a number of problems (see extensive discussion in #253), and also provides a mechanism by which readable byte streams can smuggle out "unused" buffers given to them, by using { value: zeroLengthViewOntoBuffer, done: true }.

Finally, the state property is now removed (from readable stream), since there is no longer a "waiting" vs. "readable" distinction.

This commit also adds some new infrastructure for _templated tests_, and ports some portion of the existing tests there. This is our solution for #217 and #264.

Note that we re-merged all related code into a single readable-stream.js file, as the setup with the three separate files (readable-stream.js, exclusive-stream-reader.js, and readable-stream-abstract-ops.js) was problematic in causing circular dependencies.

- Closes #253!
- Closes #266 by simplifying reader-related stuff, removing the problematic `ready` promise, and ensuring that cancel() always returns a new promise instead of reusing [[closedPromise]].
- Closes #291 since the relevant tests have been re-written and the related infrastructure around pull simplified.
- Closes #264 by introducing templated tests.

---

Branch snapshot at https://streams.spec.whatwg.org/branch-snapshots/async-read-take-3/. Sections that are good for at-a-glance understanding of the change, or sections that have seen particular rework, include:

- [New discussion of locking](https://streams.spec.whatwg.org/branch-snapshots/async-read-take-3/#locking)
- [New examples of using readable streams](https://streams.spec.whatwg.org/branch-snapshots/async-read-take-3/#rs-intro)
- New [ReadableStream](https://streams.spec.whatwg.org/branch-snapshots/async-read-take-3/#rs-class-definition) and [ReadableStreamReader](https://streams.spec.whatwg.org/branch-snapshots/async-read-take-3/#reader-class-definition) class definitions
- New [ReadableStreamReader.prototype.read()](https://streams.spec.whatwg.org/branch-snapshots/async-read-take-3/#reader-read) method definition, including non-normative description
- [New section on "other streams"](https://streams.spec.whatwg.org/branch-snapshots/async-read-take-3/#other-streams), replacing the crusty "subclassing streams" section, describing how different types of streams (e.g. ReadableStreams and putative ReadableByteStreams) share common idioms and can all interoperate with anything obeying the writable stream contract.
You can view, comment on, or merge this pull request online at:

  https://github.com/whatwg/streams/pull/296

-- Commit Summary --

  * Change the model for ReadableStream to have async read()

-- File Changes --

    M Examples.md (63)
    D Locking Design Doc.md (92)
    M index.bs (635)
    M readable-stream.svg (16)
    D reference-implementation/lib/exclusive-stream-reader.js (148)
    M reference-implementation/lib/helpers.js (10)
    D reference-implementation/lib/readable-stream-abstract-ops.js (299)
    M reference-implementation/lib/readable-stream.js (500)
    M reference-implementation/lib/transform-stream.js (4)
    M reference-implementation/run-tests.js (12)
    M reference-implementation/test/bad-underlying-sources.js (145)
    M reference-implementation/test/brand-checks.js (84)
    M reference-implementation/test/count-queuing-strategy.js (139)
    D reference-implementation/test/exclusive-stream-reader.js (531)
    M reference-implementation/test/pipe-through.js (6)
    M reference-implementation/test/pipe-to-options.js (170)
    M reference-implementation/test/pipe-to.js (668)
    M reference-implementation/test/readable-stream-cancel.js (247)
    A reference-implementation/test/readable-stream-reader.js (208)
    A reference-implementation/test/readable-stream-templated.js (165)
    M reference-implementation/test/readable-stream.js (913)
    A reference-implementation/test/templated/readable-stream-closed-reader.js (50)
    A reference-implementation/test/templated/readable-stream-closed.js (72)
    A reference-implementation/test/templated/readable-stream-empty-reader.js (134)
    A reference-implementation/test/templated/readable-stream-empty.js (21)
    A reference-implementation/test/templated/readable-stream-errored-async-only.js (59)
    A reference-implementation/test/templated/readable-stream-errored-reader.js (32)
    A reference-implementation/test/templated/readable-stream-errored-sync-only.js (33)
    A reference-implementation/test/templated/readable-stream-errored.js (51)
    A reference-implementation/test/templated/readable-stream-two-chunks-closed-reader.js (112)
    A reference-implementation/test/templated/readable-stream-two-chunks-closed.js (71)
    A reference-implementation/test/templated/readable-stream-two-chunks-open-reader.js (52)
    M reference-implementation/test/transform-stream-errors.js (62)
    M reference-implementation/test/transform-stream.js (316)
    M reference-implementation/test/utils/random-push-source.js (23)
    M reference-implementation/test/utils/readable-stream-to-array.js (20)

-- Patch Links --

https://github.com/whatwg/streams/pull/296.patch
https://github.com/whatwg/streams/pull/296.diff

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

Received on Thursday, 12 March 2015 09:18:48 UTC