节点管道到标准输出 - 我如何判断是否排空



关于确定是否需要等待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代码使程序保持活动状态,直到所有承诺都得到解决。

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

与其直接写入process.stdout,不如创建一个自定义可写的(如下所示(,它写入 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)
  });
  ...
}

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

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

正因为如此,基于我对唯一文档的假设,我想你可以依靠drain事件来知道所有数据何时得到了很好的处理或可能被清除。

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

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

最新更新