Treehouse

Synchronous Exec in Node.js

By on  

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.

ydkjs-5.png

Recent Features

  • 5 HTML5 APIs You Didn’t Know Existed

    When you say or read "HTML5", you half expect exotic dancers and unicorns to walk into the room to the tune of "I'm Sexy and I Know It."  Can you blame us though?  We watched the fundamental APIs stagnate for so long that a basic feature...

  • From Webcam to Animated GIF: the Secret Behind chat.meatspac.es!

    My team mate Edna Piranha is not only an awesome hacker; she's also a fantastic philosopher! Communication and online interactions is a subject that has kept her mind busy for a long time, and it has also resulted in a bunch of interesting experimental projects...

Incredible Demos

Discussion

  1. Brusselsblogger

    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. Artem

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

    http://pastebin.com/LkyKZi80

  3. David

    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

    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

    > 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. Mark

    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. Coder

    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.

Wrap your code in <pre class="{language}"></pre> tags, link to a GitHub gist, JSFiddle fiddle, or CodePen pen to embed!