Child Process in Nodejs

Gaurav K. Verma
4 min readMay 17, 2020

--

I have been working on nodejs for a long time. Since we all know Nodejs is not made for heavy server-side calculations. Node.js processes IOs in a non-blocking way, meaning that its single thread can manage several IO requests at the same time.

But sometimes we have to do some heavy calculations on the server-side, since nodejs is single-threaded, we can’t block the main thread for these kinds of calculations.

For these kinds of computations, we need to use the inbuilt library called child_process. Let's see why?

Child_process opens a process by creating a pipe, forking, and invoking the shell. Since a pipe is by definition unidirectional, the type argument may specify only reading or writing, not both the resulting stream is correspondingly read-only or write-only.

In simple words, child_process enable you for doing heavy computation by creating native OS or kernel threads. So, you can execute any script which that system (where you running your node script) supports.

I’m going to discuss some of the main methods from these libraries which save you from a lot of hell.

child_process.spawn

The child_process.spawn() method spawns the child process asynchronously, without blocking the Node.js event loop. The child_process.spawnSync() function provides equivalent functionality in a synchronous manner that blocks the event loop until the spawned process either exits or is terminated.

Let’s take an example

const { spawn } = require("child_process");const ls = spawn("cat", ["index.js"]);ls.stdout.on("data", (data) => {
console.log(`stdout: ${data}`);
});
ls.stderr.on("data", (data) => {
console.error(`stderr: ${data}`);
});
ls.on("close", (code) => {
console.log(`child process exited with code ${code}`);
});

Here, if we save above code as index.js, we get an output as

>> node index.js stdout: const { spawn } = require("child_process");
const ls = spawn("cat", ["index.js"]);
ls.stdout.on("data", (data) => {
console.log(`stdout: ${data}`);
});
ls.stderr.on("data", (data) => {
console.error(`stderr: ${data}`);
});
ls.on("close", (code) => {
console.log(`child process exited with code ${code}`);
});

We are here just running a shell command inside nodejs (shell-command because I'm running the script on my Linux machine).

child_process.exec

`child_process.exec() spawns a shell and runs a command within that shell, passing the stdout and stderr to a callback function when complete. It spawns a shell then executes the command within that shell, buffering any generated output.

Let’s see an example

const { exec } = require('child_process');
exec('python run.py', (err, stdout, stderr) => {
if (err) {
console.error(err);
return;
}
console.log(stdout);
});
//output v12.16.3

Here, with the help of the exec method, you can run any script just passing the command as a first parameter, and second as a callback so we can get the output from that file.

child_process.execFile

The child_process.execFile() is similar to child_process.exec() except that it does not spawn a shell by default. Rather, the specified executable file is spawned directly as a new process making it slightly more efficient than child_process.exec().

Let’s see an example

const { execFile } = require('child_process');
const child = execFile('node', ['--version'], (error, stdout, stderr) => {
if (error) {
throw error;
}
console.log(stdout);
});
//output
v12.16.3

child_process.fork

The child_process.fork() method is a special case of child_process.spawn() used specifically to spawn new Node.js processes. Like child_process.spawn(), a ChildProcess object is returned. The returned ChildProcess will have an additional communication channel built-in that allows messages to be passed back and forth between the parent and child. See subprocess.send() for details.

By default, child_process.fork() will spawn new Node.js instances using the process.execPath of the parent process. The execPath property in the options object allows for an alternative execution path to be used.

//index.jsconst { fork } = require("child_process");
const ls = fork("./child.js");
let count = 0;//exiting the thread when child process endedls.on("exit", (code) => {
console.log(`child_process exited with code ${code}`);
});
ls.on("message", (msg) => {
console.log(`PARENT: message from child process is ${msg}`);
count = parseInt(msg) + 1;
console.log("PARENT: +1 from parent");
ls.send(count);
});
//child.js
var count = Math.floor(Math.random() * 100);
process.on("message", (msg) => {
console.log("CHILD: message received from parent process", msg);
count = parseInt(msg) + 1;console.log("CHILD: +1 from child");
if (count <= 100) process.send(count);
else process.exit(1);
});
console.log(count);process.send(count);

Well, this code simply passing messages back and forth between child process and its parent. The output will be something like this:

>> node index.js
89
PARENT: message from child process is 89
PARENT: +1 from parent
CHILD: message received from parent process 90
CHILD: +1 from child
PARENT: message from child process is 91
PARENT: +1 from parent
CHILD: message received from parent process 92
CHILD: +1 from child
PARENT: message from child process is 93
PARENT: +1 from parent
CHILD: message received from parent process 94
CHILD: +1 from child
PARENT: message from child process is 95
PARENT: +1 from parent
CHILD: message received from parent process 96
CHILD: +1 from child
PARENT: message from child process is 97
PARENT: +1 from parent
CHILD: message received from parent process 98
CHILD: +1 from child
PARENT: message from child process is 99
PARENT: +1 from parent
CHILD: message received from parent process 100
CHILD: +1 from child
child_process exited with code 1

I tried to explain as simple as I can. But if you found anything missing just reach out to me in comments.

If you want to support me, please give claps to my blog and follow me,

“Lets code better”

--

--