Synchronous Exec in Node.js
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.
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
Sorry ^^. Here is the link to formated code:
http://pastebin.com/LkyKZi80
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
withjqXHR ($.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.
You don’t want to do this; it does separate concerns.
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.
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)
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)
>
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.
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.
The exec-sync is and has been working fine. Grow a pair and unwad your panties ;)
You can have your cake and eat it, too — with coroutines. Check out generators, available since Node 0.11.
Another approach to this is run a sequence of commands over a spawned shell that stays alive across many commands all executed sequentially (using streams to interact with it) such as https://github.com/bitsofinfo/stateful-process-command-proxy
Antiquated and no longer valid advice. See this question on StackOverflow for an uptodate solution that uses the standard library.. http://stackoverflow.com/q/31819950/124486
Update from the future 2017, you can use exec in a synchronous way now.
https://nodejs.org/api/child_process.html#child_process_child_process_execsync_command_options