EventEmitter位于Promises链中间

d11*_*wtq 19 node.js promise bluebird

我正在做的事情涉及按顺序运行一系列child_process.spawn()(进行一些设置,然后运行调用者感兴趣的实际多肉命令,然后进行一些清理).

就像是:

doAllTheThings()
  .then(function(exitStatus){
    // all the things were done
    // and we've returned the exitStatus of
    // a command in the middle of a chain
  });
Run Code Online (Sandbox Code Playgroud)

在哪里doAllTheThings()是这样的:

function doAllTheThings() {
  runSetupCommand()
    .then(function(){
      return runInterestingCommand();
    })
    .then(function(exitStatus){
      return runTearDownCommand(exitStatus); // pass exitStatus along to return to caller
    });
}
Run Code Online (Sandbox Code Playgroud)

在内部我正在使用child_process.spawn(),它返回一个EventEmitter,我实际上将close事件的结果runInterestingCommand()返回给调用者.

现在我还需要将data来自stdout和stderr的事件发送给调用者,调用者也来自EventEmitters.有没有办法让(Bluebird)Promises使用它,或者它们只是阻碍了发出多个事件的EventEmitters?

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

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
  });
Run Code Online (Sandbox Code Playgroud)

我能想到使我的程序工作的唯一方法是重写它以删除promise链,只需在包含setup/teardown的东西中使用原始EventEmitter,例如:

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();
  });
});
Run Code Online (Sandbox Code Playgroud)

但是,由于EventEmitters在Node.js中非常普遍,我不禁想到我应该能够让它们在Promise链中运行.有线索吗?

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

Ben*_*aum 29

有两种方法,一种提供您最初要求的语法,另一种提供代理.

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;
}
Run Code Online (Sandbox Code Playgroud)

哪个可以让你使用你想要的语法:

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
  });
Run Code Online (Sandbox Code Playgroud)

但是,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;
}
Run Code Online (Sandbox Code Playgroud)

哪个会让你这样做:

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
  });
Run Code Online (Sandbox Code Playgroud)

  • 这里是否存在多次触发错误事件的危险?这将导致承诺不止一次被拒绝,这是不可能的. (2认同)