How to create a child process in nodejs

How to create a child process in nodejs

Introduction

The main event loop of nodejs is single-threaded. Nodejs itself also maintains a Worker Pool to handle some time-consuming operations. We can also manually create new threads to perform our own tasks by using the worker_threads provided by nodejs.

This article will introduce a new way to execute nodejs tasks, child process.

Child Process

lib/child_process.js provides the child_process module, through which we can create child processes.

Note that worker_threads creates child threads, while child_process creates child processes.

In the child_process module, processes can be created synchronously or asynchronously. The synchronous creation method is just to add Sync after the asynchronous creation method.

The created process is represented by the ChildProcess class.

Let's look at the definition of ChildProcess:

interface ChildProcess extends events.EventEmitter {
 stdin: Writable | null;
 stdout : Readable | null;
 stderr: Readable | null;
 readonly channel?: Pipe | null;
 readonly stdio: [
  Writable | null, // stdin
  Readable | null, // stdout
  Readable | null, // stderr
  Readable | Writable | null | undefined, // extra
  Readable | Writable | null | undefined // extra
 ];
 readonly killed: boolean;
 readonly pid: number;
 readonly connected: boolean;
 readonly exitCode: number | null;
 readonly signalCode: NodeJS.Signals | null;
 readonly spawnargs: string[];
 readonly spawnfile: string;
 kill(signal?: NodeJS.Signals | number): boolean;
 send(message: Serializable, callback?: (error: Error | null) => void): boolean;
 send(message: Serializable, sendHandle?: SendHandle, callback?: (error: Error | null) => void): boolean;
 send(message: Serializable, sendHandle?: SendHandle, options?: MessageOptions, callback?: (error: Error | null) => void): boolean;
 disconnect(): void;
 unref(): void;
 ref(): void;

 /**
  * events.EventEmitter
  * 1. close
  * 2. disconnect
  * 3. error
  * 4. exit
  * 5. message
  */
 ...
 }

You can see that ChildProcess is also an EventEmitter, so it can send and receive events.

ChildProcess can receive five types of events: close, disconnect, error, exit and message.

The disconnect event is triggered when subprocess.disconnect() is called in the parent process or process.disconnect() in the child process.

The error event is triggered when a process cannot be created, a process cannot be killed, or a message cannot be sent to a child process.

When the child process ends, the exit event is triggered.

The close event is emitted when the child process's stdio streams are closed. Note that the close event is different from the exit event, because multiple processes may share the same stdio, so sending an exit event does not necessarily trigger a close event.

Let's look at an example of close and exit:

const { spawn } = require('child_process');
const ls = spawn('ls', ['-lh', '/usr']);

ls.stdout.on('data', (data) => {
 console.log(`stdout: ${data}`);
});

ls.on('close', (code) => {
 console.log(`The child process uses code $[code] to close all stdio`);
});

ls.on('exit', (code) => {
 console.log(`The child process exited with code $[code]`);
});

Finally, there is the message event, which is triggered when the child process sends a message using process.send().

There are several standard stream attributes in ChildProcess, namely stderr, stdout, stdin and stdio.

stderr, stdout, and stdin are easy to understand, they are standard error, standard output, and standard input respectively.

Let's look at the use of stdout:

const { spawn } = require('child_process');

const subprocess = spawn('ls');

subprocess.stdout.on('data', (data) => {
 console.log(`Received data block ${data}`);
});

stdio is actually a collection of stderr, stdout, and stdin:

readonly stdio: [
  Writable | null, // stdin
  Readable | null, // stdout
  Readable | null, // stderr
  Readable | Writable | null | undefined, // extra
  Readable | Writable | null | undefined // extra
 ];

Among them, stdio[0] represents stdin, stdio[1] represents stdout, and stdio[2] represents stderr.

If the three standard streams are set to something other than pipe when the child process is created with stdio, then stdin, stdout, and stderr will be null.

Let's look at an example using stdio:

const assert = require('assert');
const fs = require('fs');
const child_process = require('child_process');

const subprocess = child_process.spawn('ls', {
 stdio:
 0, // Use parent process's stdin for child process.
 'pipe', // Pass the child process's stdout to the parent process through the pipe.
 fs.openSync('err.out', 'w') // Direct the child process's stderr to a file.
 ]
});

assert.strictEqual(subprocess.stdio[0], null);
assert.strictEqual(subprocess.stdio[0], subprocess.stdin);

assert(subprocess.stdout);
assert.strictEqual(subprocess.stdio[1], subprocess.stdout);

assert.strictEqual(subprocess.stdio[2], null);
assert.strictEqual(subprocess.stdio[2], subprocess.stderr);

Usually, the parent process maintains a reference count to the child process, and the parent process will exit only after the child process exits.

This reference is ref, and if the unref method is called, it allows the parent process to exit independently of the child process.

const { spawn } = require('child_process');

const subprocess = spawn(process.argv[0], ['child_program.js'], {
 detached: true,
 stdio: 'ignore'
});

subprocess.unref();

Finally, let's look at how to send messages through ChildProcess:

subprocess.send(message[, sendHandle[, options]][, callback])

Here, message is the message to be sent, and callback is the callback after the message is sent.

sendHandle is special. It can be a TCP server or socket object, and pass these handles to the child process. The child process will pass the handle to the Callback function in the message event so that it can be processed in the child process.

Let's look at an example of passing a TCP server. First, let's look at the main process:

const subprocess = require('child_process').fork('subprocess.js');

// Open the server object and send the handle.
const server = require('net').createServer();
server.on('connection', (socket) => {
 socket.end('Handled by the parent process');
});
server.listen(1337, () => {
 subprocess.send('server', server);
});

Look at the subprocess again:

process.on('message', (m, server) => {
 if (m === 'server') {
 server.on('connection', (socket) => {
 socket.end('Handled by child process');
 });
 }
});

You can see that the child process receives the server handle and listens for the connection event in the child process.

Let's look at an example of passing a socket object:

onst { fork } = require('child_process');
const normal = fork('subprocess.js', ['normal']);
const special = fork('subprocess.js', ['special']);

// Start the server and send the socket to the child process.
// Use `pauseOnConnect` to prevent the socket from being read before being sent to the child process.
const server = require('net').createServer({ pauseOnConnect: true });
server.on('connection', (socket) => {

 // Special priority.
 if (socket.remoteAddress === '74.125.127.100') {
 special.send('socket', socket);
 return;
 }
 // Normal priority.
 normal.send('socket', socket);
});
server.listen(1337);

Contents of subprocess.js:

process.on('message', (m, socket) => {
 if (m === 'socket') {
 if (socket) {
 // Check if the client socket exists.
 // The socket can be closed between being sent and being received by the child process.
 socket.end(`Request is processed using ${process.argv[2]} priority`);
 }
 }
});

The main process creates two subprocesses, one for special priority and one for normal priority.

Creating a process asynchronously

The child_process module has four ways to create processes asynchronously, namely child_process.spawn(), child_process.fork(), child_process.exec() and child_process.execFile().

Let's first look at the definition of each method:

child_process.spawn(command[, args][, options])

child_process.fork(modulePath[, args][, options])

child_process.exec(command[, options][, callback])

child_process.execFile(file[, args][, options][, callback])

Among them, child_process.spawn is the basis, which will asynchronously generate a new process. Other fork, exec and execFile are all generated based on spawn.

Fork will generate a new Node.js process.

exec and execFile execute new commands in a new process with callback. The difference between them is that in the Windows environment, if you want to execute a .bat or .cmd file, you cannot do it without a shell terminal. At this time, it can only be started with exec. execFile is not executable.

Alternatively, you can use spawn.

Let's look at an example of using spawn and exec in Windows:

// On Windows only.
const { spawn } = require('child_process');
const bat = spawn('cmd.exe', ['/c', 'my.bat']);

bat.stdout.on('data', (data) => {
 console.log(data.toString());
});

bat.stderr.on('data', (data) => {
 console.error(data.toString());
});

bat.on('exit', (code) => {
 console.log(`subprocess exited, exit code $[code]`);
});
const { exec, spawn } = require('child_process');
exec('my.bat', (err, stdout, stderr) => {
 if (err) {
 console.error(err);
 return;
 }
 console.log(stdout);
});

// Script with spaces in the file name:
const bat = spawn('"my script.cmd"', ['a', 'b'], { shell: true });
// or:
exec('"my script.cmd" a b', (err, stdout, stderr) => {
 // ...
});

Synchronous creation process

To create a process synchronously, you can use child_process.spawnSync(), child_process.execSync(), and child_process.execFileSync(). The synchronous method blocks the Node.js event loop and suspends the execution of any other code until the child process exits.

Usually for some script tasks, it is more common to use synchronous creation process.

This is the end of this article about how to create a child process in nodejs. For more information about creating a child process in nodejs, please search for previous articles on 123WORDPRESS.COM or continue to browse the following related articles. I hope you will support 123WORDPRESS.COM in the future!

You may also be interested in:
  • Nodejs error handling process record
  • Detailed explanation of how to quickly operate MySQL database in nodejs environment
  • A complete example of implementing a timed crawler with Nodejs
  • Differences between this keyword in NodeJS and browsers
  • The core process of nodejs processing tcp connection
  • Detailed explanation of Nodejs array queue and forEach application
  • Learn asynchronous programming in nodejs in one article
  • How to use worker_threads to create new threads in nodejs
  • Implementation of WeChat applet message push in Nodejs
  • Example code for implementing WeChat account splitting with Nodejs
  • Detailed explanation of asynchronous programming knowledge points in nodejs
  • The simplest way to connect to the database with nodejs+express
  • How to downgrade the installed nodejs high version to a lower version in windows (graphic tutorial)
  • Detailed explanation of the implementation process of NodeJS CORS configuration
  • How to use nodejs to automatically send email reminders at regular intervals (super practical)
  • Simple deployment of nodeJs project in Alibaba Cloud
  • How to use nodejs to implement command line games
  • Understanding what Node.js is is so easy

<<:  Solution to the Chinese garbled characters problem in MySQL under Ubuntu

>>:  Solution to the problem that docker nginx cannot be accessed after running

Recommend

Several ways to set the expiration time of localStorage

Table of contents Problem Description 1. Basic so...

The difference and usage of distinct and row_number() over() in SQL

1 Introduction When we write SQL statements to op...

Detailed explanation of how to install PHP7 on Linux

How to install PHP7 on Linux? 1. Install dependen...

JavaScript+html to implement front-end page sliding verification

This article shares the specific code of JavaScri...

A summary of the reasons why Mysql does not use date field index

Table of contents background explore Summarize ba...

Analyze the problem of pulling down the Oracle 11g image configuration in Docker

1. Pull the image docker pull registry.cn-hangzho...

Vue implements graphic verification code

This article example shares the specific code of ...

Detailed explanation of key uniqueness of v-for in Vue

Table of contents 1. DOM Diff 2. Add key attribut...

Simple implementation method of two-way data binding in js project

Table of contents Preface Publish-Subscriber Patt...

JavaScript imitates Xiaomi carousel effect

This article is a self-written imitation of the X...

How to pass the value of the select drop-down box to the id to implement the code

The complete code is as follows : HTML code: Copy ...

MySQL Series 14 MySQL High Availability Implementation

1. MHA ​By monitoring the master node, automatic ...

Use HTML to write a simple email template

Today, I want to write about a "low-tech&quo...

Solution to the 404/503 problem when logging in to TeamCenter12

TeamCenter12 enters the account password and clic...

HTML+CSS+jQuery imitates the search hot list tab effect with screenshots

Copy code The code is as follows: <!DOCTYPE ht...