The child_process module translates this sentence into English.
child_process
is one of the core modules in Node.js, used to create and manage child processes. It provides various ways to execute external commands or scripts and supports inter-process communication. Through this module, Node.js can invoke system commands, run programs written in other languages, and even implement multi-process parallel task processing.
Methods for Creating Child Processes
Node.js offers four main methods for creating child processes, each suited for different scenarios:
- exec() - Executes shell commands, suitable for short-lived, small commands
- execFile() - Directly executes executable files without shell parsing
- spawn() - A low-level method suitable for long-running processes, supporting streaming data
- fork() - A specialized form of
spawn()
designed specifically for creating new Node.js processes
exec() Method
exec()
is the simplest way to create a child process. It spawns a shell to execute the command and buffers the results in memory. Once the command completes, the results are returned via a callback function.
const { exec } = require('child_process');
exec('ls -lh', (error, stdout, stderr) => {
if (error) {
console.error(`Execution error: ${error}`);
return;
}
console.log(`Standard output:\n${stdout}`);
if (stderr) {
console.error(`Standard error output:\n${stderr}`);
}
});
This method is suitable for executing simple shell commands but is not ideal for handling large amounts of output data, as all output is buffered in memory.
execFile() Method
execFile()
is similar to exec()
but executes the command directly without using a shell. This improves security by avoiding shell injection attacks.
const { execFile } = require('child_process');
execFile('node', ['--version'], (error, stdout, stderr) => {
if (error) {
throw error;
}
console.log(stdout);
});
spawn() Method
spawn()
is a lower-level API that returns a child process object with stdout and stderr streams. This method is ideal for handling large amounts of data, as the data is processed in streams.
const { spawn } = require('child_process');
const ls = spawn('ls', ['-lh', '/usr']);
ls.stdout.on('data', (data) => {
console.log(`Standard output:\n${data}`);
});
ls.stderr.on('data', (data) => {
console.error(`Standard error output:\n${data}`);
});
ls.on('close', (code) => {
console.log(`Child process exit code: ${code}`);
});
fork() Method
fork()
is a specialized version of spawn()
designed specifically for creating new Node.js processes. It automatically establishes an IPC channel, enabling communication between parent and child processes.
// parent.js
const { fork } = require('child_process');
const child = fork('./child.js');
child.on('message', (msg) => {
console.log('Message from child process:', msg);
});
child.send({ hello: 'world' });
// child.js
process.on('message', (msg) => {
console.log('Message from parent process:', msg);
process.send({ foo: 'bar' });
});
Inter-Process Communication
Node.js child processes support multiple communication methods:
- Standard I/O - Communication via stdin, stdout, and stderr streams
- IPC Channel - Processes created with
fork()
can communicate usingsend()
and themessage
event - Network - Child processes can create their own servers or clients
IPC Communication Example
// Parent process
const { fork } = require('child_process');
const child = fork('child.js');
child.on('message', (m) => {
console.log('Parent received:', m);
});
child.send({ parent: 'pid' });
// Child process (child.js)
process.on('message', (m) => {
console.log('Child received:', m);
process.send({ child: 'pid' });
});
Advanced Usage
Handling Long-Running Processes
For long-running processes, it's important to properly handle errors and exit events:
const { spawn } = require('child_process');
const server = spawn('node', ['server.js']);
server.stdout.on('data', (data) => {
console.log(`Server output: ${data}`);
});
server.stderr.on('data', (data) => {
console.error(`Server error: ${data}`);
});
server.on('close', (code) => {
console.log(`Server process exited with code ${code}`);
});
// Terminate the server after 5 seconds
setTimeout(() => {
server.kill('SIGTERM');
}, 5000);
Parallel Execution of Commands
You can use Promises and async/await to execute multiple commands in parallel:
const { exec } = require('child_process');
const util = require('util');
const execPromise = util.promisify(exec);
async function runCommands() {
try {
const [lsResult, psResult] = await Promise.all([
execPromise('ls -lh'),
execPromise('ps aux')
]);
console.log('Directory contents:', lsResult.stdout);
console.log('Process list:', psResult.stdout);
} catch (error) {
console.error('Execution error:', error);
}
}
runCommands();
Security Considerations
When using the child_process
module, keep the following security concerns in mind:
- Command Injection - Avoid directly concatenating user input into commands
- Resource Exhaustion - Limit the number of child processes and resource usage
- Sensitive Information Leakage - Be aware that child processes may access parent process environment variables
Security Example
// Unsafe approach
const userInput = 'some; rm -rf /';
exec(`ls ${userInput}`); // Dangerous!
// Safe approach
const { execFile } = require('child_process');
execFile('ls', [userInput], (err, stdout) => {
// Handle the result
});
Performance Optimization
For scenarios requiring frequent child process creation, consider the following optimizations:
- Reuse Child Processes - Keep child processes alive for long-running tasks
- Use Worker Pools - Manage a pool of child processes to avoid frequent creation/destruction
- Load Balancing - Distribute tasks evenly across multiple child processes
Worker Pool Example
const { fork } = require('child_process');
const os = require('os');
const path = require('path');
class WorkerPool {
constructor(workerPath, size = os.cpus().length) {
this.workers = [];
this.queue = [];
for (let i = 0; i < size; i++) {
const worker = fork(workerPath);
worker.on('message', (result) => {
const { resolve } = this.queue.shift();
resolve(result);
this.workers.push(worker);
this.processQueue();
});
this.workers.push(worker);
}
}
processQueue() {
if (this.queue.length > 0 && this.workers.length > 0) {
const worker = this.workers.pop();
const { task, resolve } = this.queue[0];
worker.send(task);
}
}
runTask(task) {
return new Promise((resolve) => {
this.queue.push({ task, resolve });
this.processQueue();
});
}
}
// Usage example
const pool = new WorkerPool(path.join(__dirname, 'worker.js'));
pool.runTask({ data: 'some data' }).then(console.log);
Practical Use Cases
Build Tool Integration
Many build tools use child_process
to execute external commands:
const { execSync } = require('child_process');
function buildProject() {
try {
console.log('Installing dependencies...');
execSync('npm install', { stdio: 'inherit' });
console.log('Running tests...');
execSync('npm test', { stdio: 'inherit' });
console.log('Building project...');
execSync('npm run build', { stdio: 'inherit' });
console.log('Build successful!');
} catch (error) {
console.error('Build failed:', error);
process.exit(1);
}
}
buildProject();
Service Monitoring
You can use child_process
to monitor the status of other services:
const { spawn } = require('child_process');
const http = require('http');
const serverProcess = spawn('node', ['server.js']);
serverProcess.stdout.on('data', (data) => {
console.log(`Server output: ${data}`);
});
serverProcess.stderr.on('data', (data) => {
console.error(`Server error: ${data}`);
});
// Monitoring endpoint
http.createServer((req, res) => {
if (req.url === '/health') {
res.writeHead(200);
res.end('OK');
} else if (req.url === '/restart' && req.method === 'POST') {
serverProcess.kill();
serverProcess = spawn('node', ['server.js']);
res.writeHead(200);
res.end('Server restarted');
}
}).listen(8080);
Debugging Tips
Debugging child processes can be challenging. Here are some useful tips:
- Enable Debug Output - Set
{ stdio: 'inherit' }
to see the child process's output - Capture Exit Codes - Check the child process's exit code to diagnose issues
- Use IPC for Debugging - Send debug information via the IPC channel
Debugging Example
const { spawn } = require('child_process');
const child = spawn('node', ['buggy.js'], {
stdio: ['pipe', 'pipe', 'pipe', 'ipc']
});
child.stdout.on('data', (data) => {
console.log(`Output: ${data}`);
});
child.stderr.on('data', (data) => {
console.error(`Error: ${data}`);
});
child.on('close', (code, signal) => {
console.log(`Process exited with code: ${code}, signal: ${signal}`);
});
child.on('message', (message) => {
console.log('Debug info:', message);
});
本站部分内容来自互联网,一切版权均归源网站或源作者所有。
如果侵犯了你的权益请来信告知我们删除。邮箱:cc@cccx.cn