gpt4 book ai didi

javascript - Nodejs - 流式可读可写被误解

转载 作者:数据小太阳 更新时间:2023-10-29 03:58:47 24 4
gpt4 key购买 nike

我运行一个 Node 服务器并具有以下代码:

var readable = fs.createReadStream(__dirname + '/greet.txt',
{encoding: 'utf8', highWaterMark: 332 * 1024});

问候.txt:
hello

我无法理解可读流和可写流;
在我上面的代码中,我有一个可读的流,它从 greet.txt 中读取 -
块进入缓冲区,我可以看到二进制数据......问题是,
不应该有一个可写的流将数据发送到我的另一边的缓冲区吗?二进制数据如何突然开始飞入我的缓冲区,只是不清楚。

这是可读和可写的组合:
var readable = fs.createReadStream(__dirname + '/greet.txt',
{encoding: 'utf8', highWaterMark: 332 * 1024});

var writeable = fs.createWriteStream(__dirname + '/greetcopy.txt');

readable.on('data', function(chunk){
writeable.write(chunk);
});

当一个块到达可读缓冲区,并通过一个事件被发送到可写流的缓冲区时,可写流不应该也是可读的以便接收数据吗?一旦可写流的缓冲区从可读数据中获取信息并将其发送到greetcopy.txt 文件(该文件为空),数据是如何到达的?

node 中可读和可写的概念过于简单,我很难掌握它们。谢谢你的时间,我想了解一些幕后发生的事情......

最佳答案

Node.js 流非常复杂且令人困惑。我花了大量时间试图理解它们,我将尝试在下面传达我的发现。

有 5 种类型,Readable、Writable、Duplex、Transform 和 PassThrough。

好的,首先是简单的部分:可读可写

可读

  • 要将数据添加到可读流,请使用 .push() 函数。当流完成时,你 push(null)。
  • 结束时,可读流会触发 'end' 事件。
  • 您可以通过监听 'readable' 事件然后执行 'read()' 直到它返回 null 来从可读流中读取数据。
  • 可读流有一个缓冲区,这意味着当你 'push()' 到一个缓冲区时,如果缓冲区已满,那么 push() 将返回 false。但是,您可以继续推送到缓冲区并填充它,即使它已满。 “highWaterMark”(或缓冲区大小)实际上是提供信息的。
  • 可读流实现了一个 _read() 方法来从非流源中提取数据。但是,您不必使用它。您可以将此方法留空并使用前面描述的推送方法。使用您的流的任何人都可以调用 read(),它首先从内部缓冲区读取,然后在缓冲区为空时调用 _read()。

  • 可写
  • 要将数据添加到可写流,请使用 .write() 函数。当流结束时,您使用 .end()。
  • 当您调用 .end() 时,它不会立即结束流。它将使用 process.nextTick() 在下一个滴答声结束流!这给我带来了许多比赛条件的心痛。
  • 可写流有一个缓冲区。如果缓冲区已满(highWaterMark),则调用 .write() 时它将返回 false。但是,如果需要,您可以继续写入并忽略此事件。否则,我认为会有类似“排水”事件通知您可以继续写作。
  • 可写流实现了一个 _write() 方法来将数据发送到某个后端非流接收器。如果此方法返回 false,则 Writable 流将开始缓冲数据并且不会再次调用 _write() 直到 'drain'。

  • 一起使用可读流和可写流
  • 您只能将一个可读流通过管道传输到一个可写流。这可能会让您感到困惑,因为您可能已经看到类似 'streamA.pipe(streamB).pipe(streamC)'... 等的语法。事实是,本示例中唯一的可读流是 streamA。唯一的可写流是streamC。 streamB(以及中间的任何其他流)是一种特殊的流,称为转换流。
  • 关键点 1:您不能通过管道传输到可读流。一切都必须从可读流开始。
  • 关键点 2:您不能将可写流通过管道传输到其他任何内容。可写流是它结束的地方。数据必须通过 _write method() 退出可写流。

  • 使流彼此通过管道传输的唯一方法是使用转换流。陪我到此为止?这是非常令人困惑的地方:Duplex、Transform 和 PassThrough

    双工
  • 双工流是可读和可写流的结合。当您通过管道传输双工流(或从双工流中读取)时,它作为可读流运行。当您通过管道传输到双工流时,它的运行方式与 Writable 流完全相同。
  • 关键点1:示例'streamA.pipe(duplexB).pipe(streamC)'表示从Readable streamA的_read()方法读取数据并发送到duplexB的_write()方法。它不会进入streamC。这也意味着从 duplexB 的 _read() 方法读取的数据将进入 streamC。语法令人困惑,因为看起来数据从流A 到流C 排成一行。
  • 关键点2:在使用双工流时,到底是调用.push(null)还是.end()来结束流是非常令人困惑的。是否应该听“结束”或“完成”事件也非常令人困惑。我仍然没有答案。调用 end() 是否隐式执行 .push(null)?

  • 这两个关键点使使用双工流变得非常困惑。事实上,我想要一个与上面完全一样的双向流,所以我创建了自己的 here .我称它为“链接流”,它实际上并不使用 _read 或 _write 方法。它从 streamA 获取数据并将其通过管道传输到 streamC,反之亦然,在全双工模式下,您可以监听 'finish' 或 'end' 事件,这无关紧要。这是一个真正的双向直通管道。

    转换
  • 转换流是双工流
  • 在转换流上调用 write() 在幕后调用 _write,它只调用 _read()
  • 在转换流上调用 this.push(...) 在幕后调用 _read,后者调用 _transform()
  • 基本上所有数据路径都通向 _transform() 方法。您实现了 _transform 方法。无论你如何使用流,它既可以作为可读也可以写,并且数据总是去同一个地方,_transform()方法
  • 一旦 _transform 方法被调用,数据就会被发送到它通过管道传输到的任何可写流。

  • 直通
  • 这只是一个 Transform 流,在 _transform 方法中什么也不做。

  • 所以你有它。我真的希望 Joyent 的人清理 Duplex 并减少混淆,我真的希望他们添加双向 PassThrough,所以我不必使用我上面描述的链接流方法。

    祝你好运!

    关于javascript - Nodejs - 流式可读可写被误解,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/35437744/

    24 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com