Node.js 在承诺链中间的事件发射器

Node.js 在承诺链中间的事件发射器,node.js,promise,bluebird,Node.js,Promise,Bluebird,我正在做的事情包括运行一系列的child\u process.spawn()(为了进行一些设置,然后运行调用方感兴趣的实际meati命令,然后进行一些清理) 比如: doAllTheThings() .then(function(exitStatus){ // all the things were done // and we've returned the exitStatus of // a command in the middle of a chain

我正在做的事情包括运行一系列的
child\u process.spawn()
(为了进行一些设置,然后运行调用方感兴趣的实际meati命令,然后进行一些清理)

比如:

doAllTheThings()
  .then(function(exitStatus){
    // all the things were done
    // and we've returned the exitStatus of
    // a command in the middle of a chain
  });
function doAllTheThings() {
  runSetupCommand()
    .then(function(){
      return runInterestingCommand();
    })
    .then(function(exitStatus){
      return runTearDownCommand(exitStatus); // pass exitStatus along to return to caller
    });
}
withTemporaryState(function(done){
  var cmd = runInterestingCommand();
  cmd.on('stdout', function(data){
    // process a chunk of received stdout data
  });
  cmd.on('stderr', function(data){
    // process a chunk of received stderr data
  });
  cmd.on('close', function(exitStatus){
    // process the exitStatus
    done();
  });
});
其中
doallthings()
类似于:

doAllTheThings()
  .then(function(exitStatus){
    // all the things were done
    // and we've returned the exitStatus of
    // a command in the middle of a chain
  });
function doAllTheThings() {
  runSetupCommand()
    .then(function(){
      return runInterestingCommand();
    })
    .then(function(exitStatus){
      return runTearDownCommand(exitStatus); // pass exitStatus along to return to caller
    });
}
withTemporaryState(function(done){
  var cmd = runInterestingCommand();
  cmd.on('stdout', function(data){
    // process a chunk of received stdout data
  });
  cmd.on('stderr', function(data){
    // process a chunk of received stderr data
  });
  cmd.on('close', function(exitStatus){
    // process the exitStatus
    done();
  });
});
在内部,我使用
child\u process.spawn()
,它返回一个
EventEmitter
,并且有效地将
close
事件的结果从
runInterestingCommand()
返回给调用者

现在我还需要从stdout和stderr向调用者发送
数据
事件,调用者也来自eventemitter。有没有办法通过(蓝鸟)的承诺来实现这一点,或者它们只是妨碍了发出多个事件的EventEmitter

理想情况下,我希望能够写:

doAllTheThings()
  .on('stdout', function(data){
    // process a chunk of received stdout data
  })
  .on('stderr', function(data){
    // process a chunk of received stderr data
  })
  .then(function(exitStatus){
    // all the things were done
    // and we've returned the exitStatus of
    // a command in the middle of a chain
  });
我能想到的使我的程序工作的唯一方法是重写它以删除承诺链,并在包装设置/拆卸的东西中使用原始EventEmitter,例如:

doAllTheThings()
  .then(function(exitStatus){
    // all the things were done
    // and we've returned the exitStatus of
    // a command in the middle of a chain
  });
function doAllTheThings() {
  runSetupCommand()
    .then(function(){
      return runInterestingCommand();
    })
    .then(function(exitStatus){
      return runTearDownCommand(exitStatus); // pass exitStatus along to return to caller
    });
}
withTemporaryState(function(done){
  var cmd = runInterestingCommand();
  cmd.on('stdout', function(data){
    // process a chunk of received stdout data
  });
  cmd.on('stderr', function(data){
    // process a chunk of received stderr data
  });
  cmd.on('close', function(exitStatus){
    // process the exitStatus
    done();
  });
});
但是,由于eventemitter在Node.js中非常常见,我不得不认为我应该能够让它们在承诺链中工作。有什么线索吗


实际上,我想继续使用Bluebird的原因之一是因为我想使用取消功能来允许从外部取消正在运行的命令。

有两种方法,一种提供您最初要求的语法,另一种接受委托

function doAllTheThings(){
     var com = runInterestingCommand();
     var p = new Promise(function(resolve, reject){
         com.on("close", resolve);
         com.on("error", reject);
     });
     p.on = function(){ com.on.apply(com, arguments); return p; };
     return p;
}
这将允许您使用所需的语法:

doAllTheThings()
  .on('stdout', function(data){
    // process a chunk of received stdout data
  })
  .on('stderr', function(data){
    // process a chunk of received stderr data
  })
  .then(function(exitStatus){
    // all the things were done
    // and we've returned the exitStatus of
    // a command in the middle of a chain
  });
但是,IMO认为这有点误导,最好让代表们通过:

function doAllTheThings(onData, onErr){
     var com = runInterestingCommand();
     var p = new Promise(function(resolve, reject){
         com.on("close", resolve);
         com.on("error", reject);
     });
     com.on("stdout", onData).on("strerr", onErr);
     return p;
}
这样你就可以:

doAllTheThings(function(data){
    // process a chunk of received stdout data
  }, function(data){
    // process a chunk of received stderr data
  })
  .then(function(exitStatus){
    // all the things were done
    // and we've returned the exitStatus of
    // a command in the middle of a chain
  });

请查看Bluebird API文档中有关progression的文档以及如何处理该问题。@BenjaminGruenbaum文档说API已被弃用,不应使用,但它似乎也没有回答我提出的问题?我没有跟踪进度,我只是有多个事件被触发,需要能够处理所有事件。那里的解决方案(进度的替代方案)应该适合您的情况。承诺不是事件发射器-拥有一个事件发射器并使用承诺跟踪完成情况。我也遇到了同样的问题,我发现了一篇关于此模式的好博文:。你可以向下滚动到中间,上面写着“执行系列承诺”。同意你的最后一点。谢谢你的详细回答@Benjamin Grunbaum在上一个示例中传递EventEmitter对象怎么样?不是传递几个参数吗?这里是否存在错误事件被多次触发的危险?这将导致承诺被拒绝不止一次,这是不可能的。