假设NodeJS中的可读流和与之相关的数据(on('data', ...)
)事件处理程序相对较慢,是否有可能在最后一个数据处理程序完成之前触发结束事件,如果是这样,它会过早终止该处理程序吗?或者,是否会分派并运行所有数据事件?
在我的情况下,我正在处理大文件,并希望将每个数据块提交到DB。我担心如果End在处理程序中的最后一个DB调用实际完成之前被触发,我可能会丢失最后一个或两个(或更多)记录。
事件'end'触发最后一个'data'事件。但它可能在最后一个Data处理程序完成之前发生。有可能在一个"数据"处理程序完成之前,就启动了下一个处理程序。这取决于你的代码中有什么,但是事件'data'的调用可能在之前完成。它可能会在你的代码中导致错误和问题。
如何引起问题的示例(对您自己的测试):
var fs = require('fs');
var rr = fs.createReadStream('somebigfile.jpg');
var i=0;
rr.on('data', function(chunk) {
i++;
var s = i;
console.log('readable:' + s);
setTimeout(function(){
console.log('timeout:'+s);
}, 50-i*10);
});
rr.on('end', function() {
console.log('end');
});
当启动每个'data'事件处理程序时,它将在控制台中打印。几毫秒后,它结束了。完成的顺序可能不同。
<标题>解决方案:可读流有两个模式'流动模式'和'暂停模式'。当你添加'data'事件处理程序时,你可以自动将可读流设置为流动模式。
来自文档:
当处于流模式时,从底层系统读取数据尽快提供给您的程序
在此模式下,事件将不会等待您的缓慢动作完成。您需要的是'暂停模式'。
从文档:在暂停模式下,你必须显式调用stream.read()来获取数据块数据输出。流以暂停模式启动。
换句话说:你需要数据块,你得到它,你处理它,当你准备好了,你要求新的数据块。在此模式下,您可以控制何时获取数据。
如何切换到'暂停模式':
是该流的默认模式。但是当你注册'data'事件处理程序时,它切换到'流动模式'。因此不要使用readstream.on('data',...)
相反,使用readstream.on('readable', function(){...})
时,它的火,那么它意味着流准备给数据块。使用var chunk = readstream.read();
示例来自docs:
var fs = require('fs');
var rr = fs.createReadStream('foo.txt');
rr.on('readable', function() {
console.log('readable:', rr.read());
});
rr.on('end', function() {
console.log('end');
});
请阅读文档了解更多细节,因为当流被自动切换到'流动模式'时,有更多的可能性。
使用慢处理程序和流动模式:
如果你想要/需要在"流动模式"下工作,也有解决方案。您可以暂停和恢复流。当你从readstream('data')中得到chunk时,暂停流,当你完成工作后再恢复它。
文档中的例子:
var readable = getReadableStreamSomehow();
readable.on('data', function(chunk) {
console.log('got %d bytes of data', chunk.length);
readable.pause();
console.log('there will be no more data for 1 second');
setTimeout(function() {
console.log('now data will start flowing again');
readable.resume();
}, 1000);
});
标题>