How to use Promise with exec in Node.js

Support for in web browsers has come a long way, with only good old IE11 needing a polyfill to support it. According to the documentation at MDN, “the Promise object represents the eventual completion (or failure) of an asynchronous operation, and its resulting value”. The concept is similar to Observables (available in RxJs) and Future (Java). Together with support being available in modern web browsers and the popular programming language offering support even for older web browsers, it has become much easier to write asynchronous JavaScript code in a synchronous fashion without using external libraries.

If you are using Node.js directly or indirectly (e.g. through ), you can run shell commands in your application. For example, you can check in your Electron app if Java is installed. To do this using the shell, you’d run the java -version command. The function which is executed asynchronously can be used to run shell commands. However, if you want to wait for its result then it is becoming cumbersome: instead of returning a Promise, there is a callback. Callbacks are still useful in some cases but often, we can avoid getting into “callback hell” by using Promise.

For this purpose, I needed a way to use the exec function with Promise and async/await.

How to use Promise with exec in Node.js

  1. The function below wraps the exec statement in a Promise which is returned.
  2. Now you can either use Promise.then(). Alternatively, you can make your function async and use await to get the result directly.
/**
* Executes a shell command and return it as a Promise.
* cmd {string}
* {Promise<string>}
*/
function execShellCommand(cmd) {
const exec = require('child_process').exec;
return new Promise((resolve, reject) => {
exec(cmd, (error, stdout, stderr) => {
if (error) {
console.warn(error);
}
resolve(stdout? stdout : stderr);
});
});
}

Example usage: check if Java is installed on the device using Node

Here is some example code to check if Java is installed on a device using above function. We use await to get the result of the shell command and log it to the console.

const javaInfo = await execShellCommand('java -version');
console.log(javaInfo);
/* Prints out:
java version "1.6.0_27"
Java(TM) 2 Runtime Environment, Standard Edition (build 1.6.0_27-b07)
Java HotSpot(TM) Client VM (build 1.6.0_27-b13, mixed mode, sharing)
*/

You could argue why I am resolving either stdout or stderr. I am mainly using this function to check if certain things are installed on a device. While checking Java installation status returns stdout, checking Gradle installation status returns stderr even though stderr is the correct log result.

Conclusion

Thank you for reading this article. Promise is a great feature which enables JavaScript developers to write better asynchronous code in a synchronous matter. As you can easy, it is easy to wrap operations in Promises and waiting for the result. Thus, we can avoid getting into “callback hell” and keep our code cleaner.

Senior Software Engineer @LeanIX. Co-founder of Sedeo. Passion for software engineering and startups. Looking forward to build great things. 有難うございます。🚀

Senior Software Engineer @LeanIX. Co-founder of Sedeo. Passion for software engineering and startups. Looking forward to build great things. 有難うございます。🚀