user3552178 user3552178 - 6 months ago 63
Node.js Question

What's the difference between async.waterfall and child_process.execSync?

say if this is linux shell, what i want to do is:

copy file1 tmp
rename tmp file2


i can do waterfall

function copyFile(cb) {
child_process.exec('cp file1 tmp', function (error, stdout, stderr) {
......
});
}
async.waterfall([
copyFile,
renameFile
], function (error) {
if (error) {
//handle readFile error or processFile error here
}
});


or guess i can do

child_process.execSync('cp file1 tmp");
child_process.execSync('rename tmp file2');


What's the difference please ? e.g performance ? blocking ?
Thanks very much !

Answer

The primary difference here is execSync which would be blocking and exec would be non-blocking. execSync blocks the creating process until the child_process created using execSync returns. exec immediately returns and will return a value if there is one later on and won't block the creating parent process. Otherwise, how they behave outside of the blocking is identical.

async.waterfall is a control flow mechanism that just guarantees that operations are executed in order and chain return values from the first function in the chain to the last function in the chain. If one of the functions passed to async.waterfall contains code that would be blocking then async.waterfall would also be blocked. async.waterfall doesn't make the guarantee that all code executed inside it will be async.

The use of child_process means that this will be executed on a separate process and not on the main process being executed using node. You shouldn't use child_process for control flow as there is overhead associated with creating and destroying a new child process. Unless you're doing some CPU intensive tasks or have a need for a separate process you should avoid this.

If you want to execute things synchronously you can wrap all of your code in a try/catch block but I would definitely say don't use child_process for control flow.

From a performance perspective, both of these approaches are bad as they create a child_process but, exec() would be better as it at least returns immediately to the creating process allowing other code to continue executing. Whenever blocking code is used in Node, you're eliminating the primary benefit of using Node. There are situations where blocking is necessary, like requiring modules, but in most scenarios there is a non-blocking alternative.

As an aside, if you're trying to copy a file you can use the fs module and pipe the original file into a new file in a new destination with a new name. The below approach is async, and doesn't require any external dependencies or control flow library. Additionally, it should be more performant than any of the code you've implemented above.

var fs = require('fs');

function copy (src, dest) {
    var r = fs.createReadStream(src);
    var w = fs.createWriteStream(dest);

    r.pipe(w);
}