EventEmitter in the middle of the Promises chain

I do what the sequence of the sequence child_process.spawn() includes in order (to do some tweaking, and then run the actual meat command that the caller is interested in, then do some cleanup).

Something like:

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

Where doAllTheThings() is something like:

 function doAllTheThings() { runSetupCommand() .then(function(){ return runInterestingCommand(); }) .then(function(exitStatus){ return runTearDownCommand(exitStatus); // pass exitStatus along to return to caller }); } 

Internally, I use child_process.spawn() , which returns an EventEmitter , and I effectively return the result of the close event from runInterestingCommand() back to the caller.

Now I also need to send data events from stdout and stderr to the caller, which are also from EventEmitters. Is there a way to do this work with (Bluebird) Promises, or do they just interfere with EventEmitters that emit more than one event?

Ideally, I would like to write:

 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 }); 

The only way I can work on my program is to rewrite it to remove the promise chain, and just use the raw EventEmitter inside what wraps the install / disable, something like:

 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(); }); }); 

But since EventEmitters are so common in all Node.js, I can't help but think that I should be able to get them to work in Promise chains. Any clues?

In fact, one of the reasons I want to use Bluebird is because I want to use the revoke functions to allow cancellation of the current command from the outside.

+16
promise bluebird
Aug 09 '14 at 7:38
source share
1 answer

There are two approaches: one provides the syntax that you originally requested, and the other delegates.

 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; } 

Which allows you to use your desired syntax:

 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 }); 

However, IMO is somewhat misleading, and it may be advisable to delegate delegates to:

 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; } 

What would you do:

 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 }); 
+25
Aug 10 '14 at 13:28
source share



All Articles