多个侦听器从NodeJS中的同一流读取

时间:2018-06-28 06:47:26

标签: node.js

我需要两个不同的侦听器来读取来自可读流的输入。 他们似乎有比赛条件,我想确保我做对了...

当我使用.on('data')时-每个侦听器都返回相同的块并可以读取它。

当我使用.on('read')时-捕获事件的第一个侦听器将从缓冲区读取,而第二个侦听器将获得空缓冲区?

这意味着当我有两个侦听器时,我无法使用.on('read')事件吗?

4 个答案:

答案 0 :(得分:7)

  1. 发出可读事件时,两个侦听器都在侦听。但是,第一个调用 read()函数将获取数据,第二个调用将获取空缓冲区,因为同一输入流被读取两次,并且只存在一个块。

  2. 发出 data 事件时,侦听器将接收从流中读取的数据块。因此,所有侦听器都接收相同的数据。

[编辑] 的详细工作方式:

所有可读流都以两种模式开始:已暂停。默认情况下,所有可读流都以暂停模式开始,但是可以使用以下三种方法中的任何一种将它们切换为流模式: 1.将“数据”事件处理程序附加到流
2.调用stream.resume()方法
3.调用stream.pipe()方法将数据发送到Writable。

使用上述任何一种方法时,流开始流动。不管 data 侦听器是否已附加到流中,都有可能丢失数据。在内部,在流上调用 read()方法,并且读取内部缓冲区中累积的所有数据并将其发送给侦听器。内存使用率很低。

在流上附加可读侦听器时,它优先于数据侦听器,因此您的流保持在已暂停模式。在暂停模式下,您必须通过调用 read()方法从内部缓冲区中显式读取数据。当可读数据可用时,它将继续积累在内部缓冲区中,直到显式调用read()方法或恢复流为止。您可以指定要从内部缓冲区读取的块的大小(以字节为单位),或者返回所有可用数据。当read()调用 data 时,也会与读取的数据块一起发出事件。使用完此数据后,将清空内部缓冲区。因此,当您附加了多个可读事件并尝试从同一内部缓冲区使用数据时,将无法多次获取相同的数据。

我对您的建议是只有一个可读侦听器和多个数据侦听器。 可读性可让您在需要时灵活阅读,而不会丢失任何数据。借助 data 事件处理程序,您将能够在所有处理程序中获取该数据。

答案 1 :(得分:3)

TL; DR :data事件将把数据发送到任意数量的侦听器,但前提是该侦听器将在读取数据之前被附加,所以请使用pipe将数据复制到两个PassThrough流并分别从每个流中读取的方法。

详细信息如下:

首先我们需要了解的是:每个数据流只能产生data事件,而每个数据块只能产生一次。这是因为流对象不“知道”正在阅读的人,仅阅读了响应即可。

现在,只要阅读您的问题我就会回答-怎么了?该事件将运行两次,因为将调用每个数据事件侦听器...除非您实际上在readable事件中设置了侦听器...

让我们假设您设置了以下内容:

response.on("data", function A(chunk) {...});
response.on("readable", function B() {
    response.on("data", function C(chunk) {...});
});

现在,当1A()到来时将收到块:1。如果流drain之后,(这意味着响应太慢,无法提供任何新数据),它将暂停。只有在此之后,流才可以再次变为readable,然后B()函数将为C() ... but ...函数{{1} }我们已经在读取A()了,因此chunk仅适用于下一个流。

现在,正如Swati Anand提到的那样,您可以使用相同的事件侦听器-但在我看来,这将杀死流的全部美感。相反,使用C()会更优雅,像这样:

pipe

其背后的想法是-我们不监听原始流上的任何事件,而是创建两个类似于“克隆”的直通事件,并在其中读取const PassThrough = require('stream').PassThrough; const data1 = new PassThrough(); const data2 = new PassThrough(); response.pipe(data1).on("data", function A(){...}); response.pipe(data2); // when you're ready data2.on("data", function C(){...}); 。这样,程序的每个部分都不会丢失任何数据。

node.js stream docs实际上是有关数据流的最佳读物。尝试将其读为管道连接的管道等故事。

答案 2 :(得分:1)

您可以使用RxJS简化以下操作

start

答案 3 :(得分:0)

tldr

const stream = require('stream');

const pt = new stream.PassThrough();

response.pipe(pt).on("data", data => {
  // process the data
});

pt.on("data", data => {
  // observe the data
);