ReadableStream

ReadableStreamストリーム API のインターフェイスで、バイトデータの読み取り可能なストリームを表します。 Fetch API は、 ReadableStream の具体的なインスタンスをResponse オブジェクトの body プロパティを介して提供します。

ReadableStream移譲可能オブジェクトです。

コンストラクター

ReadableStream()

指定されたハンドラーから読み取り可能なストリームのオブジェクトを作成して返します。

インスタンスプロパティ

ReadableStream.locked 読取専用

論理値で、読み取り可能なストリームがリーダーにロックされているかどうかを返します。

静的メソッド

ReadableStream.from() Experimental

指定された反復可能オブジェクトまたは非同期反復可能オブジェクト(配列、集合、非同期ジェネレーターなど)から ReadableStream を返します。

インスタンスメソッド

ReadableStream.cancel()

ストリームがキャンセルされたときに解決する Promise を返します。このメソッドを呼び出されると、コンシューマーがストリームへの関心を失ったことを通知します。与えられた reason 引数は基になるソースに与えられ、使用する場合と使用しない場合があります。

ReadableStream.getReader()

リーダーを作成し、ストリームをロックします。 ストリームがロックされている間は、このリーダーが解放されるまで他のリーダーを取得できません。

ReadableStream.pipeThrough()

変換ストリームまたはその他の書き込み可能/読み取り可能なペアを介して、現在のストリームをパイプ接続するチェーン可能な方法を提供します。

ReadableStream.pipeTo()

現在の ReadableStream を指定された WritableStream に接続し、 Promise を返します。これはパイピングプロセスが正常に完了したときに履行され、エラーが発生した場合は拒否されます。

ReadableStream.tee()

tee メソッドは、この読み取り可能なストリームを tee し、結果の 2 つの分岐を含む 2 要素配列を新しい ReadableStream インスタンスとして返します。 これらの各ストリームは、同じ着信データを受信します。

非同期の反復処理

ReadableStream非同期反復可能プロトコルを実装しています。 これにより、 for await...of 構文を使用して、ストリーム内のチャンクを非同期に反復処理することができます。

js
const stream = new ReadableStream(getSomeSource());

for await (const chunk of stream) {
  // それぞれの 'chunk' で何かをする
}

非同期イテレーターは、データがなくなるか、さもなければ終了するまでストリームを消費します。 ループは breakthrowreturn ステートメントによって早期に終了することもできます。

反復処理中は、他のコンシューマーがリーダーを取得できないようにストリームがロックされます(既にロックされているストリームを反復処理しようとすると TypeError が発生します)。 このロックはループが終了すると解除されます。

既定値では、ループを終了するとストリームも取り消される可能性があり、使用できなくなります。 ループを抜けた後もストリームを使用し続けるには、ストリームの values() メソッドに { preventCancel: true } を渡してください。

js
for await (const chunk of stream.values({ preventCancel: true })) {
  // 'chunk' で何かをする
  break;
}
// ストリームのためのリーダーを取得し、読み取りを続ける ...

ストリームのフェッチ

次の例では、別のリソースからフェッチした HTML の断片をブラウザーにストリーミングするために、人工的な Response が作成されます。

これは Uint8Array と組み合わせた ReadableStream の使用方法を示しています。

js
fetch("https://www.example.org")
  .then((response) => response.body)
  .then((rb) => {
    const reader = rb.getReader();

    return new ReadableStream({
      start(controller) {
        // 次の関数は各データチャンクを処理します
        function push() {
          // done は論理値で、value は Uint8Array です
          reader.read().then(({ done, value }) => {
            // 読み取るデータがもうない場合
            if (done) {
              console.log("done", done);
              controller.close();
              return;
            }
            // データを取得し、コントローラー経由でブラウザーに送信します
            controller.enqueue(value);
            // コンソールにログを出力してチャンクを調べる
            console.log(done, value);
            push();
          });
        }

        push();
      },
    });
  })
  .then((stream) =>
    // ストリームで応答する
    new Response(stream, { headers: { "Content-Type": "text/html" } }).text(),
  )
  .then((result) => {
    // Do things with result
    console.log(result);
  });

非同期イテレーターをストリームへ変換

静的な from() メソッドは、イテレーターを変換します。例えば ArrayMap, (非同期)イテレーターを読み取り可能なストリームへ変換します。

js
const myReadableStream = ReadableStream.from(iteratorOrAsyncIterator);

from() メソッドに対応していないブラウザーでは、代わりに自分自身で独自の読み取り可能なストリームを作成して同じ結果を得ることができます。

js
function iteratorToStream(iterator) {
  return new ReadableStream({
    async pull(controller) {
      const { value, done } = await iterator.next();

      if (done) {
        controller.close();
      } else {
        controller.enqueue(value);
      }
    },
  });
}

for await...of を用いたストリームの非同期反復処理

この例では、 fetch() レスポンスを処理するために for await...of ループを使用して、到着したチャンクを反復処理する方法を示します。

js
const response = await fetch("https://www.example.org");
let total = 0;

// Iterate response.body (a ReadableStream) asynchronously
for await (const chunk of response.body) {
  // Do something with each chunk
  // Here we just accumulate the size of the response.
  total += chunk.length;
}

// Do something with the total
console.log(total);

仕様書

Specification
Streams Standard
# rs-class

ブラウザーの互換性

BCD tables only load in the browser

関連情報