1. 導入:なぜストリーム処理が重要なのか
Webサイトやアプリケーションで大きなデータを読み込む際、従来の方法では「データ全体がダウンロードされるまで待機」してから処理を開始していました。しかし、これではユーザーは長い間待たされることになります。
ここで重要になるのが「ストリーム処理」です。データを小さな塊(チャンク)として順次受け取ることで、ダウンロード完了を待たずに処理を開始できるため、体感速度を劇的に改善できます。今回は、Web APIのFetchなどで利用されるResponseオブジェクトのストリーム活用法を解説します。
2. 基礎知識:ストリームとは何か
Webにおけるストリームとは、連続的に流れてくるデータの流れのことです。Responseオブジェクトの body プロパティは「ReadableStream」という仕組みを提供しています。
・ReadableStream: データを読み取るためのインターフェースです。
・チャンク: データが細分化された断片のことです。一度にすべてをメモリに展開するのではなく、届いた分から処理することでメモリ消費を抑えることができます。
3. 実装・解決策:ReadableStreamの読み取り手順
ストリームを扱うには、getReader() メソッドを使用してリーダーを取得し、ループ処理の中でread()メソッドを呼び出します。これにより、データが到着するたびに非同期で処理を進めることが可能になります。
4. サンプルプログラム
以下のコードは、APIからデータを取得し、ストリームを使用してコンソールに逐次出力する例です。
async function fetchStreamData(url) {
// 1. リクエストを送信
const response = await fetch(url);
// 2. ボディをストリームとして取得
const reader = response.body.getReader();
const decoder = new TextDecoder(); // バイナリを文字列に変換する準備
let result = '';
while (true) {
// 3. データの塊(チャンク)を読み取る
const { done, value } = await reader.read();
// 4. データが終了したらループを抜ける
if (done) break;
// 5. チャンクをテキストに変換して処理
const chunk = decoder.decode(value, { stream: true });
console.log('受信したデータ:', chunk);
result += chunk;
}
console.log('全ての受信が完了しました');
}
// 実行例
fetchStreamData('https://jsonplaceholder.typicode.com/posts');
5. 応用・注意点:現場で役立つポイント
・メモリ管理: 大容量のファイルを扱う際、一度にすべてをメモリに保持するとブラウザがクラッシュする可能性があります。ストリームを使うと、処理済みのデータを破棄できるため、メモリ使用量を一定に保てます。
・エラーハンドリング: ストリーム処理中にネットワークが切断されることもあります。必ず try…catch ブロックで囲み、エラーが発生した際の再試行処理などを検討してください。
・ブラウザ対応: 近代的なブラウザであればほぼすべて対応していますが、古い環境で開発を行う場合は、念のため「ReadableStream API」のサポート状況をCan I Useなどで確認することをおすすめします。
ストリーム処理を使いこなせば、ユーザー体験を損なわない高速なデータ通信が実現できます。まずは小さなテキストデータから試してみてください!