节点管道到标准输出——如何判断是否耗尽?

sha*_*unc 5 stream node.js

关于确定是否需要等待drainevent on的标准建议process.stdout是检查它在写入时是否返回 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);
Run Code Online (Sandbox Code Playgroud)

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

编辑

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

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

where streamcan beprocess.stdout或其他东西,其中有另一个直通流通过管道输送到其中。

我的程序在每次resolve被调用时都会退出——我认为Promise代码让程序保持活动状态,直到所有的承诺都得到解决。

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

Cra*_*cks 6

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

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

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

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

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

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