在最后一个“数据”事件之后触发事件“结束”。但它可能发生在最后一个数据处理程序完成之前。有可能在一个“数据”处理程序完成之前,下一个开始。这取决于您的代码中的内容,但稍后对事件“数据”的调用可能会在更早之前完成。它可能会导致您的代码出现错误和问题。
如何导致问题的示例(针对您自己的测试):
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');
});
当启动每个“数据”事件处理程序时,它将在您的控制台中打印。几毫秒后完成。完成可能有不同的顺序。
解决方案:
可读流有两种模式“流动模式”和“暂停模式”。当您添加“数据”事件处理程序时,您会自动将可读流设置为流动模式。
来自documentation:
在流动模式下,从底层系统读取数据并
尽快提供给您的程序
在这种模式下,事件不会等待您的慢动作完成。您需要的是“暂停模式”。
来自文档:
在暂停模式下,您必须显式调用 stream.read() 来获取块
的数据。流以暂停模式开始。
换句话说:你需要大块数据,你得到它,你使用它,当你准备好时,你请求新的数据块。在这种模式下,您可以控制何时获取数据。
如何更改为“暂停模式”:
这是此流的默认模式。但是当您注册“数据”事件处理程序时,它会切换到“流动模式”。因此不要使用readstream.on('data',...)
而是在触发时使用readstream.on('readable', function(){...}),这意味着流已准备好提供数据块。要获取大量数据,请使用var chunk = readstream.read();
来自文档的示例:
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') 时,暂停流,当你完成工作时,然后恢复它。
文档示例:
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);
});