2016-10-04 WHATWG Streams の覚書 (2)
2016-10-03 も書いたが bouzuya/whatwg-streams-example で whatwg/streams の参考実装を試している。進捗はほとんどない。src/ から test/ に code を移しているくらいだ。
WHATWG Streams のことを分かる範囲ですこしだけ書いておく。前提として昨日 (2016-10-03) 書いたとおり Model を読んでいるものとする。
WHATWG Streams は 3 つの Stream class が登場する。
ReadableStreamWritableStreamTransformStream
ReadableStream は underlying source の wrapper だ。underlying source から enqueue() された chunk を internal queue に持つ。consumer はそれを読み取る。high-level な操作としては pipeTo() で WritableStream に pipe できたり、pipeThrough() で TransformStream に pipe できる。ほかに tee() で分岐できる、これはまたあとで触れる。low-level な操作としては getReader() で read() できる。high-level な操作も内部では getReader() を使う。
ReadableStream もっとも重要な点は reader をひとつしか持てない (lock) 点だ。ReadableStream は getReader() を呼び出すと reader が得られる。この reader が lock を開放するまで、ReadableStream は getReader() を呼び出せない。pipeThrough() / pipeTo() / tee() はすべて getReader() を使用するので同様だ。RxJS Observable や Node.js Stream との一番の違いはここだと思う。
ちなみに tee() の場合は、その ReadableStream を lock する代わりに新たな ReadableStream をふたつ返す。それらを getReader() すれば複数での読み取りは困らないだろう。
WritableStream は underlying sink の wrapper だ。producer から writer で write() された chunk を internal queue に持つ。underlying sink に write() する。ReadableStream の対なので難しい点はない。もちろん getWriter() は low-level な操作だし、 WritableStream を lock する。
TransformStream は ReadableStream と WritableStream をまとめたものだ。pipeThrough() に渡す。現状の仕様には何も書かれていない。参考の実装を見た範囲では現状 readable と writable property でそれらを返すようになっているだけだ。pipeThrough() の実装を読むと TransformStream への要求が分かりやすい。
pipeThrough({ writable, readable }, options) {
this.pipeTo(writable, options);
return readable;
}
ここまでで分かるとおり ReadableStream / WritableStream / TransformStream で pipe chain をつくる。主な流れは次のとおりだ。 underlying source -> ReadableStream -> TransformStream -> WritableStream -> underlying sink 。
とりあえず今日はここまで。
覚書: underlying source / underlying sink こそ使うことに触れていない。 API について書いてから触れる。back pressure には触れてない。queuing strategy を調べてから触れる。