Synchronous Exec in Node.js

Written by David Walsh on August 15, 2012 · 11 Comments

Everyone loves NodeJS in part because it embraces a non-blocking philosophy;  interactions are asynchronous and thus, theoretically, allow for faster all-around processing.  When creating a simple script for my upcoming redesign, I found the asynchronocity ... annoying.  I was quickly sinking into callback hell with the server executions I was running through Node.js.  Luckily I found a great package called exec-sync which allows synchronous execution of shell commands so that I don't find myself many callbacks deep.

Installing exec-sync

The exec-sync package is available via npm:

npm install exec-sync

Don't you love package management?!

Using execSync

exec-synce works like any other Node.js component;  require it and it's ready to use:

// Require the dependency
var execSync = require("exec-sync");

// The traditional way
var exec = require('child_process').exec;
exec('ORIGINAL COMMAND', function(err, stdout, stderr) {
	// React to callback

	exec('SOME OTHER COMMAND', function(err2, stdout2, stderr2) {
		// More reacting

		// ... more nesting that isn't desired
	});
});

// The execSync way

var execSync = require("exec-sync");

// Create the JavaScript dir, uglify contents
execSync("cp -R "  + sourceDir + "js " + jsDir);
doCompress && walkAndDo("js", jsDir, function(fileName, stat) {
	execSync("./node_modules/uglify-js/bin/uglifyjs -nc --reserved-names 'require,define,curl,z' --unsafe --lift-vars --overwrite " + fileName);
});

// Copy the "crons" and "cache" directories over
execSync("cp -R " + sourceDir + "crons " + dirPath + "crons");
execSync("cp -R " + sourceDir + "cache " + dirPath + "cache");

// Delete all bullshit ".DS_Store" files
execSync("find . -type f -name .DS_Store -exec rm -rf {} +");

// And when all is done, copy to another place
execSync("mv " + dirPath + " ../../../wp-content/themes/jack"); 

Note that instead of passing a callback to the execSync method, I can simply assume things are running from the top down, allowing me to avoid a bunch of nested callbacks that would only muddy up my code.  Of course some processes could be asynchronous but exec-sync allows me to keep a top-down thought process. Node.js does have utilities for a few of these functions, but running shell keeps the code shorter.

The code above was just a tiny snippet of my build file. Without exec-sync, I would either need to nest and nest and nest callbacks, or get a Deferred implementation to handle all the callbacks. Using a Deferred implementation would allow for more speed for the build process, but when the process takes only a few seconds, the tradeoff for top-down execution is worth it.

Comments

  1. Brusselsblogger August 15, 2012

    A few days ago I also tried to find a solution to the sometimes annoying asynchronous way of how code is executed in node.js.

    I then discovered that there are a multitude of solutions to deal with flow control in node.js (one being exec-sync).

    After some research I decided to go with https://github.com/kriskowal/q/ as it is one of the most popular and complete module. I like the concept of “promises” and it turns out that jQuery has a similar technique with it deferred object. For me, promises were difficult to understand, but this article helped a lot: http://erickrdch.com/2012/06/how-to-wait-for-2-asynchronous-responses-on-nodejs-commonjs-promises.html

  2. Sorry ^^. Here is the link to formated code:

    http://pastebin.com/LkyKZi80

  3. Been hearing a lot about NodeJS recently. Seems like something worth picking up. I’m a server-end developer, so my experiences with front-end developing are fleeting. =)

    Also worth note is… well… a note. On jQuery’s AJAX page: http://api.jquery.com/jQuery.ajax/
    “As of jQuery 1.8, the use of async: false with jqXHR ($.Deferred) is deprecated; you must use the complete/success/error callbacks.”

    Seems like synchronous ajax calls are out the door for jQuery at the moment.

  4. You don’t want to do this; it does separate concerns.

  5. I think there’s some confusion here. I know how to hand asynchronous actions and I’m well aware of Deferreds in Dojo and jQuery.

    My point with this post is that there are times when synchronous, top-down execution is preferred.

  6. Billy Moon September 13, 2012

    after installing (and calling) execSync, I get warning in my code output:

    “Utf8String” type is deprecated, use “CString” instead

    Version installed…

    exec-sync@0.1.4 ../../../../../../node_modules/exec-sync
    └── ffi@1.0.1 (ref-struct@0.0.3, debug@0.6.0, bindings@1.0.0, ref@0.1.2)

  7. This saves the stdout to a tmp/file then reads it back correct? I guess as long as this is used for build files this should be good (according to the stackoverflow people)

  8. naikrovek March 21, 2013

    > npm install exec-sync

    if only it were that easy. I just tried it on three machines, all with python and visual studio, and it failed on each one.

    Maintainers of this and execSync need better software, or better software documentation.

  9. I too have failed to install. It seems even with python and .net that this npm still fails. First time I’ve had such a hard time installing too.

  10. The exec-sync is and has been working fine. Grow a pair and unwad your panties ;)

  11. You can have your cake and eat it, too — with coroutines. Check out generators, available since Node 0.11.

Be Heard

Tip: Wrap your code in <pre> tags or link to a GitHub Gist!

Use Code Editor
Older
text-align: start & RTL
Newer
CSS Tooltips