GitHubでの1年以上の発展期間を経て,プロジェクトStreamsはWHATWGによって,WebストリーミングAPIの標準化作業に採用されることになった。プロジェクトを率いるDomenic Denicola氏は,現在はECMAScript 6の一部となったPromisesの頃から作業に携わっている人物だ。
APIの目的は,"データストリームを生成,構成,使用する"ために,低レベルのI/Oプリミティブへのマッピングを提供することにある。これらはつまり,ファイルI/Oやソケット,マルチメディア,あるいはプロセス間通信といった,より高レベルな他のAPIの基盤として使用可能な生のストリームなのだ。その背景には,Web上のデータ全体をメモリにフェッチしすることなく,必要に応じたデータへのアクセスと取得できなくてはならない,という事情がある。
標準では"Readable", "Writable", "Transform"という,3タイプのストリームが提案されている。ReadableとWritableストリームのユースケースは自明だが,もうひとつのTransformストリームは,データのオンザフライでの暗号化/復号化,イメージの圧縮/展開,あるいはビデオへのフィルタ適用などで使用するためのものだ。
ストリームが扱うのはデータのチャンクである。チャンクは,ストリームの処理するデータの基本ユニットを表すものだ。チャンクの内容はバイナリでもテキストでもよい。異なるタイプのチャンクを組み合わせることもできる。オブジェクトデータを処理の対象にすべきかどうかは,今でも議論されている部分だ。
ストリームは,その基礎となるソースを取り囲むラッパである。Readableストリームでは,そのようなソースとして2つのタイプがある。プッシュソース – ユーザに対してデータをプッシュするとともに,プッシュ処理の停止と再開のメカニズムも備える。プルソース – ユーザからの要求を基本として,同期ないし非同期モードでデータを提供する。ストリームはこれら2つのタイプのソースの上に,統一されたインターフェースを提供する。
プロデューサ(Producer)が,Writableストリームにデータを送る。ストリームは連続的な書き込みをキューし,それをひとつずつ,その基礎となるシンクに引き渡す。
Transformストリームは,ReadableストリームとWritableストリームのパイプとして動作する。複数のTransformストリームをひとつにまとめて,パイプチェーンを形成することも可能だ。 パイプはシグナルに基づくバックプレッシャ機構を備えていて,ストリームのひとつがオーバーロードになると,それが全体に通知される。ストリームはそれぞれ,バッファリングアプローチを利用したデータ処理を行う。次のストリームあるいは基礎となるシンクに対する変換を実行する順番が回ってくるまで,チャンクをキュー内に保持しておく。これらのキューを使ったキューイング方法によって,バックプレッシャ機構が実現されている。キューイング方式は,例えばストリームのひとつが3つ以上のチャンクをキューに持った場合に,バックプレッシャを発生させる,というようなものだ。
標準に合わせて,ECMAScript 6で記述されてTraceurを使ってECMAScript 5に変換された,リファレンス実装とテストが提供されている。Chromiumにストリームサポートを追加する初期段階の実装もある。
我々はDenicola氏から,プロジェクトに関する詳しい情報を聞いた。
InfoQ: ストリームが有用であることは承知していますが,すでにWeb上の至るところにあります。なぜ今,新たなストリーミングAPIが必要なのでしょう?
DD: 確かに多くのWebサイトで,基本技術として使われています。ですが,どれも開発者が操作できるようなものではありません。例えばXMLHttpRequestを行う場合,その応答データを取得するには,そのすべてを一括してメモリに格納する以外に方法がないのです。これはつまり,例えばブラウザで<video>ストリーミングなどの実装にストリーミング技術を利用しようとしても,開発者自身がXMLHttpRequestを使ってそれを行う手段が存在しない,ということになります。ストリーム標準(Streams Standard)の考え方は,おそらくはすでに利用されてはいるものの,開発者がアクセスを許されていない基本部分のストリーム機能を改めて公開する上で,共通のJavaScriptデータタイプを提供する,ということにあります。
InfoQ: 将来的にはECMAScriptに含まれる形になるのでしょうか?
DD: 面白い質問ですね。実際に私たちは,次のTC39ミーティングでその話をするつもりです[1]が,少し迷っています。それは別として,I/Oストリームそれ自体は十分に抽象化されていますし,仕様としても,環境に依存しないような方法で記述されています。大規模な標準ライブラリを備えた言語,例えばC++やJava,C#などは,ストリームを組み込みで備えています。それに比べて,ECMAScriptの標準ライブラリは昔から規模が小さい上に,言語レベルのプリミティブを重視したものでした。I/Oのようなものには,あまり関心が払われていなかったのです。ですから,ストリームのようなものは前例がありませんし,多少は物議を醸し出すかも知れませんね。
現時点では,標準はそれ自体で独立させておいて,JavaScriptの言語仕様に組み込まない,というのが最も理にかなった方法だと思っています –– ですが,実装はブラウザに限らず,たくさんのJS環境に存在するようになるでしょうね。例えば,初期化を扱うECMA-402は完全に独立した仕様ですが,さまざまなJS環境で実装されています。WHATWG URL標準[3]はNode.jsのURL解析ライブラリより後で開発されたものですが,将来的にはNodeの実装の方が,URL標準に合うように更新されるのではないかと期待しています。あるいはFetch標準[4]のようなものであっても,理屈から言えば,HTTP要求を処理する標準的な方法として,たくさんの異なるJS環境に実装できるはずです。
[1]: https://github.com/tc39/agendas/blob/master/2014/11.md
[2]: http://www.ecma-international.org/publications/standards/Ecma-402.htm
[3]: http://url.spec.whatwg.org/
[4]: https://fetch.spec.whatwg.org/
InfoQ: Blinkにはストリームの初期実装がありますが,それ例外にストリームに興味を示しているところはありますか?
DD: もちろんです! MicrosoftとMozillaとは積極的に話をしています。どちらも自分たちのブラウザでストリームをサポートすることに,強い関心を持っているのです。まだ初期の段階ですが,たくさんの支援を受けています。