javascriptnode.jspromisebluebird

How to promisify Node's child_process.exec and child_process.execFile functions with Bluebird?


I'm using the Bluebird promise library under Node.js, it's great! But I have a question:

If you take a look at the documentation of Node's child_process.exec and child_process.execFile you can see that both of these functions are returning a ChildProcess object.

So what's the recommended way to promisify such functions?

Note that the following works (I get a Promise object):

var Promise = require('bluebird');
var execAsync = Promise.promisify(require('child_process').exec);
var execFileAsync = Promise.promisify(require('child_process').execFile);

But how can one get access to the original return value of the original Node.js functions? (In these cases I would need to be able to access the originally returned ChildProcess objects.)

Any suggestion would be appreciated!

EDIT:

Here is an example code which is using the return value of the child_process.exec function:

var exec = require('child_process').exec;
var child = exec('node ./commands/server.js');
child.stdout.on('data', function(data) {
    console.log('stdout: ' + data);
});
child.stderr.on('data', function(data) {
    console.log('stderr: ' + data);
});
child.on('close', function(code) {
    console.log('closing code: ' + code);
});

But if I would use the promisified version of the exec function ( execAsync from above ) then the return value will be a promise, not a ChildProcess object. This is the real problem I am talking about.


Solution

  • It sounds like you'd like to return two things from the call:

    So "the recommended way to promisify such functions"? Don't.

    You're outside the convention. Promise returning functions are expected to return a promise, and that's it. You could return an object with two members (the ChildProcess & the promise), but that'll just confuse people.

    I'd suggest calling the unpromisified function, and creating a promise based off the returned childProcess. (Maybe wrap that into a helper function)

    This way, it's quite explicit for the next person who reads the code.

    Something like:

    var Promise = require('bluebird');
    var exec = require('child_process').execFile;
    
    function promiseFromChildProcess(child) {
        return new Promise(function (resolve, reject) {
            child.addListener("error", reject);
            child.addListener("exit", resolve);
        });
    }
    
    var child = exec('ls');
    
    promiseFromChildProcess(child).then(function (result) {
        console.log('promise complete: ' + result);
    }, function (err) {
        console.log('promise rejected: ' + err);
    });
    
    child.stdout.on('data', function (data) {
        console.log('stdout: ' + data);
    });
    child.stderr.on('data', function (data) {
        console.log('stderr: ' + data);
    });
    child.on('close', function (code) {
        console.log('closing code: ' + code);
    });
    

    If you're just wanting to promisify specifically child_process.exec() and child_process.execFile(), in recent node versions there is a better answer here.