generated at
ストリーム
stream
データの流れ(stream)を扱うデータ構造
データの塊が非同期的に繰り返し流れてくる
非同期処理になるのがイテレータ との違い

例:巨大なファイルをまとめて読み書きするとパフォーマンス上の問題が出る
js
async function copyFile(src, dest) { const data = await fs.readFile(src); // ここでファイル全体をBufferに読み込んでいる return await fs.writeFile(dest, data); // ここでBufferからファイル全体を書き込んでいる }
データの内容が全部メモリに載るのでメモリが圧迫される
データの内容がデカすぎてデータ構造に入りきらない
Node.jsのBufferには2147483647bytes以上のデータが入らない
ストリームを使い、ファイルを少しずつ読み込んで少しずつ書き込むことで効率を高める
js
async function copyFileStream(src, dest) { return new Promise((resolve) => fs .createReadStream(src) .pipe(fs.createWriteStream(dest)) .on("finish", resolve) ); }

非同期IOだけでは不十分
fs.createReadStream でファイルから内容を読みだすReadableStreamを作る
fs.createWriteStream でファイルに内容を書き込むWritableStreamを作る
かつての JavaScript (つか Node.js) ではイベントで処理してた
on-data.js
stream.on("data", chunk => { console.log(`data: ${chunk}`); }) stream.on('error', error => { console.error(`error: ${error}`) }) stream.on('end', () => { console.log(`end.`) })
現在の ECMAScript では AsyncIterator が実質的にストリームとして扱える
for-await-of 構文で手続き的に扱える
当たり前だが実行をブロックする
for-await-of.js
try { for await(const chunk of stream) { console.log(`data: ${chunk}`); } } catch (error) { console.error(`error: ${error}`); } console.log(`end.`)

『Callback to Promise and beyond 』