ストリーム
Streams API ↗は、JavaScriptがプログラム的にデータのストリームにアクセスし、処理することを可能にするウェブ標準APIです。
- ReadableStream
- ReadableStream BYOBReader
- ReadableStream DefaultReader
- TransformStream
- WritableStream
- WritableStream DefaultWriter
ワーカーは、event.respondWith()に応答ボディ全体を準備する必要はありません。フロントマター(つまり、HTTPステータスラインとヘッダー)を送信した後に応答ボディをストリーミングするためにTransformStreamを使用できます。これにより、次のことを最小限に抑えることができます:
- 訪問者のタイム・トゥ・ファースト・バイト。
- ワーカーで行われるバッファリング。
バッファリングを最小限に抑えることは、ワーカーのメモリ制限を超える応答ボディを処理または変換する場合に特に重要です。これらのケースでは、ストリーミングが唯一の実装戦略です。
ワーカーは、ReadableStreamをボディとして使用してResponseオブジェクトを作成できます。ReadableStreamを通じて提供されるデータは、利用可能になるとクライアントにストリーミングされます。
export default { async fetch(request, env, ctx) { // オリジンサーバーから取得します。 let response = await fetch(request);
// ... そして、その処理が実行されている間に応答を提供します。 return new Response(response.body, response); }}addEventListener('fetch', event => { event.respondWith(fetchAndStream(event.request));});
async function fetchAndStream(request) { // オリジンサーバーから取得します。 let response = await fetch(request);
// ... そして、その処理が実行されている間に応答を提供します。 return new Response(readable.body, response);}TransformStreamとReadableStream.pipeTo()メソッドを使用して、ストリーミング中に応答ボディを変更できます:
export default { async fetch(request, env, ctx) { // オリジンサーバーから取得します。 let response = await fetch(request);
let { readable, writable } = new TransformStream({ transform(chunk, controller) { controller.enqueue(modifyChunkSomehow(chunk)); } });
// ボディのポンピングを開始します。注意:awaitはしません! response.body.pipeTo(writable);
// ... そして、その処理が実行されている間に応答を提供します。 return new Response(readable, response); }}addEventListener('fetch', event => { event.respondWith(fetchAndStream(event.request));});
async function fetchAndStream(request) { // オリジンサーバーから取得します。 let response = await fetch(request);
let { readable, writable } = new TransformStream({ transform(chunk, controller) { controller.enqueue(modifyChunkSomehow(chunk)); } });
// ボディのポンピングを開始します。注意:awaitはしません! response.body.pipeTo(writable);
// ... そして、その処理が実行されている間に応答を提供します。 return new Response(readable, response);}この例では、response.body.pipeTo(writable)を呼び出しますが、awaitはしません。これは、fetchAndStream()関数の残りの進行をブロックしないようにするためです。応答が完了するか、クライアントが切断されるまで非同期に実行され続けます。
ランタイムは、応答がクライアントに返された後も関数(response.body.pipeTo(writable))を実行し続けることができます。この例では、サブリクエストの応答ボディを最終的な応答ボディにポンピングします。ただし、ボディにプレフィックスやサフィックスを追加したり、何らかの方法で処理したりするなど、より複雑なロジックを使用することもできます。
- MDNのStreams APIドキュメント ↗
- Streams API仕様 ↗
- 最適化された体験のためにESモジュール構文でワーカーコードを書く。