JavaScript/ReadableStreamDefaultReader
ReadableStreamDefaultReaderオブジェクト
概要
ReadableStreamDefaultReader
は、ストリームからデータを逐次的に読み取るためのインターフェースを提供します。このオブジェクトを使用することで、ReadableStream
からチャンクごとにデータを取得し、非同期処理することが可能になります。
基本的な使い方
ReadableStreamDefaultReader
は、ReadableStream
のgetReader()メソッドを呼び出すことで取得できます。
const response = await fetch('https://example.com/data'); const reader = response.body.getReader();
プロパティとメソッド
ReadableStreamDefaultReader
には以下のプロパティとメソッドが含まれています。
closed
closedプロパティは、ストリームが閉じられたときに解決するPromiseを返します。
const reader = stream.getReader(); reader.closed.then(() => { console.log('ストリームが閉じられました'); });
cancel(reason)
cancelメソッドは、ストリームの読み取りをキャンセルします。
const reader = stream.getReader(); // 読み取りをキャンセル reader.cancel('読み取りを中止します').then(() => { console.log('ストリームの読み取りがキャンセルされました'); });
read()
readメソッドは、ストリームから次のチャンクを読み取ります。このメソッドは、{ value, done }
オブジェクトを含むPromiseを返します。doneがtrueの場合、ストリームの終わりに達したことを意味します。
const reader = stream.getReader(); async function readStream() { while (true) { const { value, done } = await reader.read(); if (done) { console.log('ストリームの読み取りが完了しました'); break; } console.log(`受信したデータ: ${value}`); } } readStream();
releaseLock()
releaseLockメソッドは、リーダーのロックを解除し、他のリーダーがストリームを読み取れるようにします。
const reader = stream.getReader(); // 何らかの処理を行った後... reader.releaseLock(); // 別のリーダーで読み取りが可能になる const anotherReader = stream.getReader();
実践的な例:テキストファイルの読み取り
下記は、fetch
を使ってテキストファイルを取得し、ReadableStreamDefaultReader
を使って処理する例です。
async function readTextFile(url) { const response = await fetch(url); const reader = response.body.getReader(); const decoder = new TextDecoder('utf-8'); let result = ''; while (true) { const { value, done } = await reader.read(); if (done) break; // Uint8Arrayをテキストに変換 const chunk = decoder.decode(value, { stream: true }); result += chunk; // 処理中の経過を表示 console.log(`${result.length}バイト読み込みました`); } return result; } readTextFile('https://example.com/sample.txt') .then(text => { console.log('ファイルの内容:', text); }) .catch(error => { console.error('エラーが発生しました:', error); });
ReadableStreamDefaultReaderとジェネレーターの組み合わせ
ストリームを使いやすく処理するために、ジェネレーター関数と組み合わせることができます。
async function* streamAsyncIterator(stream) { const reader = stream.getReader(); try { while (true) { const { value, done } = await reader.read(); if (done) return; yield value; } } finally { reader.releaseLock(); } } async function processStream() { const response = await fetch('https://example.com/data'); const decoder = new TextDecoder(); for await (const chunk of streamAsyncIterator(response.body)) { const text = decoder.decode(chunk); console.log('チャンク:', text); } } processStream();
エラー処理
ReadableStreamDefaultReader
を使用する際は、適切なエラー処理を行うことが重要です。
async function safelyReadStream(stream) { const reader = stream.getReader(); try { while (true) { const { value, done } = await reader.read(); if (done) break; // データの処理 console.log('データチャンク:', value); } } catch (error) { console.error('ストリーム読み取り中にエラーが発生しました:', error); } finally { // リーダーのロックを必ず解除 reader.releaseLock(); } }
ReadableStreamDefaultReaderの状態と戻り値
メソッド | 戻り値 | 説明 |
---|---|---|
read() | Promise<{value: any, done: boolean}> | 次のチャンクを読み取り、値とストリームの状態を返す |
cancel(reason) | Promise<void> | ストリームをキャンセルし、完了すると解決するPromise を返す |
releaseLock() | void | リーダーのロックを解除する(戻り値なし) |
closed | Promise<void> | ストリームが閉じられたとき、またはエラーが発生したときに解決または拒否されるPromise を返す |
互換性とブラウザサポート
ReadableStreamDefaultReader
は比較的新しいAPIであり、一部の古いブラウザではサポートされていない場合があります。必要に応じてポリフィルを使用することも検討してください。
// ブラウザの互換性をチェックする簡単な方法 if (typeof ReadableStream === 'undefined') { console.warn('このブラウザはReadableStreamをサポートしていません。ポリフィルが必要かもしれません。'); }
このようにReadableStreamDefaultReader
は、大きなファイルや長時間にわたるデータ転送を効率的に処理するための強力なツールです。ストリーミングAPIを活用することで、メモリ使用量を最小限に抑えながら大量のデータを処理することができます。