このdrain
イベントは、書き込み可能なストリームの内部バッファーが空になったときのものです。
これは、内部バッファーのサイズがそのhighWaterMark
プロパティを超えた場合にのみ発生します。これは、データ ソースからの読み取りを停止するまで、書き込み可能なストリームの内部バッファー内に格納できるデータの最大バイト数です。
このような問題の原因は、あるストリームからのデータ ソースの読み取りが、別のリソースへの書き込みよりも高速であることが原因である可能性があります。たとえば、次の 2 つのストリームがあります。
var fs = require('fs');
var read = fs.createReadStream('./read');
var write = fs.createWriteStream('./write');
ここで、ファイルread
が SSD 上にあり、500MB/s で読み取ることwrite
ができ、HDD 上にあると想像してください150MB/s
。書き込みストリームが追いつかなくなり、内部バッファにデータを格納し始めます。バッファーが に到達するhighWaterMark
と (デフォルトでは 16KB)、書き込みが を返し始めfalse
、ストリームは内部的にドレインをキューに入れます。内部バッファの長さが 0 になると、drain
イベントが発生します。
ドレインの仕組みは次のとおりです。
if (state.length === 0 && state.needDrain) {
state.needDrain = false;
stream.emit('drain');
}
これらは、writeOrBuffer
機能の一部であるドレインの前提条件です。
var ret = state.length < state.highWaterMark;
state.needDrain = !ret;
イベントがどのようにdrain
使用されるかを確認するには、Node.js ドキュメントの例を参照してください。
function writeOneMillionTimes(writer, data, encoding, callback) {
var i = 1000000;
write();
function write() {
var ok = true;
do {
i -= 1;
if (i === 0) {
// last time!
writer.write(data, encoding, callback);
} else {
// see if we should continue, or wait
// don't pass the callback, because we're not done yet.
ok = writer.write(data, encoding);
}
} while (i > 0 && ok);
if (i > 0) {
// had to stop early!
// write some more once it drains
writer.once('drain', write);
}
}
}
関数の目的は、書き込み可能なストリームに 1,000,000 回書き込むことです。変数ok
が true に設定され、が true の場合にのみループが実行されok
ます。ループの反復ごとに、 の値が の値にok
設定され、stream.write()
a が必要な場合は false が返されますdrain
。false になるとok
、イベント ハンドラーがdrain
待機し、発生すると、書き込みを再開します。
特にコードに関してはdrain
、ストリームを開いた直後に一度だけ書き込むため、イベントを使用する必要はありません。ストリームにはまだ何も書き込んでいないため、内部バッファーは空であり、drain
イベントを発生させるには、少なくとも 16 KB のチャンクを書き込む必要があります。イベントは、書き込み可能なストリームdrain
の設定よりも多くのデータを何度も書き込むためのものです。highWaterMark