1 of 17

Fetch with Streams

Apr. 2015

2 of 17

Requirements

  • この機能を使用するには、Chrome dev もしくは Chrome canary が必要です
  • chrome://flags で “Enable experimental Web Platform features” を有効にしてください

3 of 17

Fetch API (as of Chrome 42)

fetch(‘https://example.com/’).then(function(res) {

return res.text();

}).then(function(text) {

// We have the body string here!

console.log(text);

});

var promise = res.text();

promise は、ダウンロードが終わらないと fulfill されない

  • 進捗を知りたい
  • 途中までのデータを見て処理を変えたい
  • 無限データを受け取りたい
  • 全部のデータを覚えておきたくない

4 of 17

XMLHttpRequest

var xhr = new XMLHttpRequest();

xhr.open(‘https://example.com/’);

xhr.onprogress = function() {

var responseSoFar = xhr.responseText;

...

};

xhr.send();

XMLHttpRequest には、progress event が配信される

テキストを受け取っている時のみ、途中のレスポンスボディが見られる

5 of 17

Fetch API vs. XHR

Fetch API

XHR text

XHR binary

progress event

NG

OK

OK

partial result

NG

OK ただし、すでに読んだ結果を忘れられない

NG

6 of 17

Fetch API vs. XHR

Fetch API

XHR text

XHR binary

Fetch API + Streams

progress event

NG

OK

OK

OK

partial result

NG

OK ただし、すでに読んだ結果を忘れられない

NG

OK

7 of 17

producer

consumer

data (text, arraybuffer, object, …)

8 of 17

producer

data

ReadableStream

consumer

data

WritableStream

9 of 17

producer

consumer

rs.pipeTo(ws)

10 of 17

ReadableStream

interface ReadableStream {

void cancel(optional any reason);

ReadableStreamReader getReader();

}

  • ReadableStream から直接データを読むことはできない
  • データを読むには、getReader() でreader を取得する
  • アクティブな reader がいる場合、getReader() は失敗する

11 of 17

ReadableStreamReader

interface ReadableStreamReader {

void cancel(optional any reason);

readonly attribute Promise<undefined> closed;

Promise<any> read();

void releaseLock();

}

  • reader は readable, closed, errored の状態を取る
  • 最後まで読むと closed 状態に遷移して、reader が解放される
  • releaseLock() で reader を解放することができる
    • 解放すると、reader は closed 状態に遷移する
  • エラーが起きた場合、reader は解放される
  • closed Promise は、reader が closed 状態に遷移したとき fulfill され、errored 状態に遷移したとき reject される

12 of 17

ReadableStreamReader.read

var promise = reader.read().then(function(r) {

if (r.done) {

// done!

} else {

var data = r.value;

}

});

  • read メソッドで非同期にデータを読むことができる

13 of 17

Example: consume

function consume(reader) {

var chunks = [];

function rec() {

return reader.read().then(function(r) {

if (r.done) { return chunks; }

else {

chunks.push(r.value);

return rec();

}

});

}

return rec();

}

14 of 17

WritableStream

TBD

15 of 17

interface Response {

...

readonly attribute ReadableByteStream body;

}

fetch(‘https://example.com/’).then(function(res) {

return consume(res.body.getReader());

}).then(function(chunks) {...});

  • ReadableByteStream ≒ ReadableStream<ArrayBufferView>
  • text() などの手続きは、内部でストリームからデータを読んでいるかのように動作する
    • ストリームがロックされている時は手続きが失敗する
    • 手続きの動作中は getReader() が失敗する

16 of 17

TODO

  • バイナリストリームからの、サイズ指定読み込み
    • 「レスポンスの、最初の四バイトを読め」
  • Writable[Byte]Stream 仕様化、実装
  • Request.body 及び アップロードストリーム
  • Backpressure 実装
  • Developer constructible streams

17 of 17