我有此代码:
const { Writable } = require('stream')
let writable = new Writable({ highWaterMark: 10 })
writable._write = (chunk, encoding, cb) => {
process.stdout.write(chunk)
}
function writeData(iterations, writer, data, encoding, cb) {
(function write() {
if (!iterations--) return cb()
if (!writer.write(data, encoding)) {
console.log(` <wait>: highWaterMark reached`)
writer.once('drain', write) // same result when I comment this line
}
})()
}
writeData(4, writable, 'String longer than highWaterMark', 'utf8', () => console.log('Done'))
当我注释检查'drain'
事件以再次写入的代码时,我得到相同的结果。
String longer than highWaterMark <wait> highWaterMark reached
似乎Node会自动执行此操作,所以为什么要烦扰我们自己手动监听'drain'
事件?
答案 0 :(得分:1)
如果您不等待drain
事件,节点将继续缓冲您的块,直到出现最大的内存使用量为止。
一旦达到highWaterMark
阈值,节点将尝试刷新缓冲区并写入磁盘,但这会在事件循环的下一个周期发生,因此如果您不等待(继续写入) ,这永远不会发生。
当我注释检查代码的代码时,我得到相同的结果 'drain'事件再次写入。
您将获得相同的最终结果,因为您没有多次调用.write
(足以达到内存限制)。但是,如果您对正在写入的文件执行tail -f
,则将看到直到进程退出或writeData
函数在这种情况下结束之前都没有写入任何内容。但是,如果您不顾一切,您将看到进程仍在运行时正在写入文件(highWaterMark
字节)。
不用等待,您的代码将阻止事件循环,直到文件被完全写入为止,这几乎与使用fs.writeFileSync
相同。因此,如果您在具有成千上万个并发请求的服务器上执行此操作,您将了解等待耗尽事件发生的重要性。
您可以检查此问题,在这里您将看到.write
进行缓冲的方式以及如果您不等待消耗事件发生的情况:why does attempting to write large a large file cause js heap to run out of memory
似乎Node会自动执行此操作,所以为什么要打扰我们自己 手动监听“排水”事件?
当您使用.pipe
而不是.write
const read = fs.createReadStream('/tmp/file.txt');
const write = fs.createWriteStream('/tmp/copy.txt');
read.pipe(write); // You don't have to handle `drain`