node.js - "readable"事件发生两次

标签 node.js stream node.js-stream

var fs = require('fs');

var file = fs.createReadStream('./zeros.txt');
var dataSize = 0;

file.on('readable', function () {
    var data = file.read(10);
    console.log('readable size = ', data.length);
    console.log(data.toString());
});

文件“zeros.txt”包含 700 个字符“0”

据我所知,在调用 read(10) 之后,stream 必须停止并等待新的 read() 调用。然而,调用的结果:

readable size =  10
0000000000
readable size =  10
0000000000

最佳答案

在 Node.js 将文件(全部或部分,取决于文件本身的大小)加载到缓冲区(使用 push() 方法)后,它会发出 readable 事件表示一些数据已经被读入缓冲区并可以使用了。然后在你调用read(10)之后,你将释放缓冲区,然后Node.js会再次自动填充缓冲区并再次发出readable事件以指示有还有一些数据要从缓冲区中读取。如果您调用 read(700),则不会再次发出下一个 readable 事件

流动和非流动模式

与监听数据事件 时不同,流将保持所谓的非流动模式。这意味着开发人员将负责释放流(从流中读取)。另一方面,当监听一个数据事件时,流会自动进入所谓的流动模式,这意味着流本身将负责释放自己,即流会填充和清空自己,直到他底层系统(在这种情况下,zero.txt 将被完整读取)。请注意,缓冲区将在任一模式下自动填充数据。

流动模式

非流动模式的示例,我们必须手动清空缓冲区(使用 read() 方法):

var fs = require('fs'),
util = require('util');

// I have increased the file size to 19 MB (about 19 mln characters);
// Cause of the buffer capicity.
var file = fs.createReadStream('./zeros.txt'); 
var dataSize = 0;

// Readable will be called when the buffer has been filled with data.
// Initially Node.js will fill the buffer with data automatically,
// so this event will be called automatically aswell of course.
// Once the buffer will be free again after the first fill, Node.js
// will fill the buffer automatically again. Node.js just watches this stream
// and makes sure to fill it, when there is still some unread data in the zero.txt file.
file.on('readable', function() {
var i = 0; // we will count how many times did while loop, for fun

// If the buffer will be empty Node will write data to the buffer
// automatically, we don't have to care about that. However
// you can specify the buffer capicty manually if you want.
console.log('loading more data from the underlying system');

// This will make the stream read 1000 bytes
// it will also return a value NULL if there is not enough 
// data to read from the buffer (meaning buffer has been fully read 
// or there is still some data but you are trying to read 1000 bytes 
// and there is less than 1000 bytes left)
while(file.read(1000) !== null) {
    i++;
}
// At this moment while loop has read everything from the buffer.
// The buffer is now empty. After this comment console.log will execute
// Node.js will fill the buffer again with new data automatically.
// And then the 'readable' event will fire again.
console.log("had to loop: " + i + " times before the buffer was empty");
})

控制台的最后几个结果:

loading more data from the underlying system
had to loop: 66 times before the buffer was empty
loading more data from the underlying system
had to loop: 65 times before the buffer was empty
loading more data from the underlying system
had to loop: 66 times before the buffer was empty
loading more data from the underlying system
had to loop: 46 times before the buffer was empty
loading more data from the underlying system
had to loop: 1 times before the buffer was empty

非流动模式

那是非流动模式,因为我们必须手动释放缓冲区。现在我们将继续流动模式。在Readable Stream 上设置data 事件监听器 将流从初始非流动模式 切换为流动模式 .这意味着缓冲区将自动清空。 Node.js 会将数据作为参数传递给 data 事件监听器,一旦该函数执行,缓冲区将再次清空,如果底层源缓冲区中仍有一些数据,将自动填充新数据,然后数据事件将再次发出。注意:如果您正在监听 data 事件和 readable 事件 两者都会触发,但 data 事件监听器 将首先清空缓冲区然后readable 事件 将触发,因此您的 read() 将始终返回 NULL

var fs = require('fs'),
util = require('util');

var file = fs.createReadStream('./zeros.txt');
var dataSize = 0;

file.on('data', function() {
    // Once this listener will stop executing new data will be read
    // into the buffer and then the 'data' event will be emitted
    // again.
    console.log('data has been loaded and emptied!')
})

file.on('readable', function () {
    // Notice we want to try to read 1 byte from the buffer
    // but in the console we see that the read() method
    // resulted in NULL, which means that the buffer is empty.
    // That's of course because we enterd the flowing mode
    // by setting up the 'data' event. (In flowing mode)
    // after the execution of the 'data' event all data
    // from the buffer will be read, but the execution
    // of listeners will continue. After all the event listeners
    // attached to this stream will execute, Node.js will fill
    // the buffer automatically again.
    console.log('readable ' + file.read(1))
});

控制台的最后几个结果:

data has been loaded and emptied!
readable null
data has been loaded and emptied!
readable null
data has been loaded and emptied!
readable null
data has been loaded and emptied!
readable null
data has been loaded and emptied!
readable null

关于node.js - "readable"事件发生两次,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/21549161/

相关文章:

node.js - 将中间件添加到单个路由 Js Express 的最简洁方法

javascript - 如何在 Nodejs 中将用户的电话号码设置为密码恢复选项

java - 在单个 Java 进程中处理多个 Kinesis 流

javascript - gulp中vinyl-buffer和gulp-streamify的目的是什么?

node.js - 在 Istio/kubernetes 中需要自定义身份验证方面的帮助

node.js - Mongoose ,将默认设置为空且唯一

c - 为什么 PDcurses 显示的字符串与源文件和流不同?

json - Node 流 : remote stream is returning JSON, 但在 ('data' 上)显示缓冲区

node.js - 从管道 HTTP 流中删除 header

Node.Js Through2-修改流