【问题标题】:Node pipe to stdout -- how do I tell if drained?节点管道到标准输出 - 我如何判断是否已耗尽?
【发布时间】:2015-10-17 19:01:24
【问题描述】:

确定是否需要等待process.stdout 上的drain 事件的标准建议是检查它在写入时是否返回false。

我应该如何检查我是否已将另一个流通过管道传输到它?在实际写入所有输出之前,该流似乎可以发出finish。我可以这样做吗?

upstreamOfStdout.on('finish', function(){
  if(!process.stdout.write('')) {
    process.stdout.on('drain', function() { done("I'm done"); });
  }
  else {
    done("I'm done"); 
  }
});
upstreamOfStdout.pipe(process.stdout);

我更喜欢不依赖于任何流内部的答案。刚刚考虑到流符合节点流接口,那么规范的方法是什么?

编辑

更大的上下文是一个包装器:

new Promise(function(resolve, reject){
  stream.on(<some-event>, resolve);
  ... (perhaps something else here?)
});

其中stream 可以是process.stdout 或其他东西,其中有另一个直通流通过管道输送到其中。

每当调用resolve 时,我的程序都会退出——我假设Promise 代码会保持程序处于活动状态,直到所有承诺都得到解决。

我已经多次遇到这种情况,并且一直使用 hack 来解决问题(例如,process.stdout 中有几个私人成员很有用。)但我真的很想一劳永逸地解决这个问题(或知道这是一个错误,因此我至少可以跟踪问题并在解决问题时修复我的 hack):我如何判断另一个流下游的流何时完成处理其输入?

【问题讨论】:

    标签: node.js stream


    【解决方案1】:

    不要直接写入process.stdout,而是创建一个自定义可写(如下所示),作为副作用写入标准输出。

    const { Writable } = require('stream');
    function writeStdoutAndFinish(){
      return new Writable({
        write(chunk, encoding, callback) {
          process.stdout.write(chunk,callback);
        },
      });
    };
    

    writeStdoutAndFinish() 的结果将发出一个finish 事件。

    async function main(){
      ...
      await new Promise((resolve)=>{
        someReadableStream.pipe(writeStdoutAndFinish()).on('finish',()=>{
          console.log('finish received');
          resolve();
        }) 
      });
      ...
    }
    

    在实践中,我不认为上述方法的行为与

    async function main(){
      ...
      await new Promise((resolve)=>{
        (someReadableStream.on('end',()=>{
          console.log('end received');
          resolve();
        })).pipe(process.stdout)
      });
      ...
    }
    

    【讨论】:

    • 抱怨...好的:) ...即使变通方法没有问题,仍然应该有更好的方法来“原则上”执行此操作。
    【解决方案2】:

    首先,据我从documentation 看到的,该流永远不会发出finish 事件,因此您不太可能依赖它。

    此外,从上面提到的文档中,drain 事件似乎用于在.write 方法返回false 时通知用户stream 何时准备好接受更多数据。在任何情况下,您都可以推断这意味着所有其他数据都已写入。从write 方法的文档中,我们确实推断出false 值(又名请停止推送数据)不是强制性的,您可以随意忽略它,但后续数据可能会填充在内存中,以便使用它长大了。

    因此,基于我对唯一文档的假设,我想您可以依靠 drain 事件来了解所有数据何时已得到妥善处理或可能被清除。

    也就是说,在我看来,还没有一种明确的方法可以明确知道所有数据何时已有效发送到控制台。

    最后,您可以监听管道streamend 事件,以了解它何时已被完全消耗,无论它是否已写入控制台或数据仍缓冲在控制台流中。 当然,你也可以随意忽略这个问题,因为一个完全消耗的流应该由node.js很好地处理,因此被丢弃,一旦你将它传送到第二个流,你就不必再处理它了。

    【讨论】:

    • 我遇到的问题是,如果没有听漏,程序会在所有内容写入之前终止,但如果我听漏,它有时永远不会发生。我认为只有在缓冲数据时才会发出排水,但我不知道数据是否被缓冲。他们似乎没有记录的方式来询问流是否已完成写入。
    • write 方法返回false 时,就会发生缓冲,或者至少文档中是这样描述的。因此drain 事件发生在这种情况之后。请记住,只要您在要执行的循环中有一些有意义的东西,您的程序就会保持活动状态。您是否尝试过收听end 事件的第一个流,而不是最后一个?
    • 我相信 end 对于可写流已被弃用——finish 是要监听的事件。正如您从我的示例代码中看到的那样,我确实听完了。您对“当 write 方法返回 false 时发生缓冲”是正确的——当前的问题是当您因为使用管道发送数据而看不到 write 返回时该怎么办。例如,在收到来自上游官方认可的finish 后写入一个空字符串?我将非常感谢维护者的回复,或对他们所写内容的引用,因为文档似乎没有定论。
    • end 事件未被弃用,请注意finish 永远不会在stdout 上发出(根据文档)。
    • 嗯...end is no longer in the documentation for a writable stream at least?process.stdout 文档中似乎没有添加任何内容。 (?)(另请注意 - 请参阅示例代码 - 我在上游流上监听 finish。)您是否在某处引用了 end 不推荐用于可写流?
    猜你喜欢
    • 2019-04-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-03-28
    • 1970-01-01
    相关资源
    最近更新 更多