跳转到内容

子进程基础与核心概念

核心模块

js
const { spawn, exec, execFile, fork } = require('child_process');

核心概念

1. 进程类型

  • 同步执行execSync/spawnSync(阻塞事件循环)
  • 异步执行:常规方法(非阻塞)

2. 进程通信(IPC)

  • 默认无通信通道
  • fork() 会自动建立 IPC 通道
  • 通过 .send()process.on('message') 通信

3. 方法对比表

方法特点输出处理适用场景
spawn流式处理事件流长时间运行/大数据量
exec缓存完整输出回调返回简单命令/小输出
execFile直接执行文件exec执行可执行文件
forkNode 专用/自带 IPC事件+IPC多进程计算

基础代码示例

同步执行

js
const { execSync } = require('child_process');
const result = execSync('ls -l', { encoding: 'utf8' });
console.log(result);  // 直接获取完整输出

异步 spawn

js
const ls = spawn('ls', ['-lh', '/usr']);

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

ls.on('close', (code) => {
  console.log(`退出码: ${code}`);
});

简单 exec

js
exec('cat *.js | wc -l', (error, stdout, stderr) => {
  if (error) throw error;
  console.log(`行数: ${stdout}`);
});

✅ 最佳实践

方法选择策略

  • 需要流式处理 → spawn
  • 执行文件 → execFile
  • 需要安全环境 → 避免 shell:true

资源管理

  • 始终监听 exit/close 事件
  • 手动销毁超时进程:
js
const controller = new AbortController();
spawn('sleep', ['10'], { signal: controller.signal });
setTimeout(() => controller.abort(), 1000);

性能优化

  • 大文件处理使用流式 I/O
  • CPU 密集型任务使用 fork() + IPC

⚠️ 常见问题

僵尸进程

  • 现象:父进程未正确监听子进程退出
  • 解决:必须添加错误和退出事件监听器
js
const child = spawn('bad_command');
child.on('error', (err) => { /* ... */ });
child.on('exit', (code) => { /* ... */ });

Shell 注入

  • 高危代码
    js
    exec(`ls ${userInput}`); // 用户输入可能包含 ; rm -rf /
  • 修复方案
    js
    execFile('ls', [sanitizedInput]); // 参数自动转义

流未消费

  • 现象:未监听 stdout/stderr 导致缓冲区填满
  • 解决:必须消费流或直接忽略:
js
spawn('cmd', [], { 
  stdio: ['ignore', 'pipe', 'pipe'] // 显式配置流
});

Windows 兼容性

  • 路径分隔符使用 path 模块处理
  • 执行 .bat/.cmd 文件需显式指定 shell
js
spawn('cmd.exe', ['/c', 'myfile.bat']);

总结备忘

要点关键决策点
输出量大小大 → spawn / 小 → exec
需要实时输出必须使用 spawn
执行第三方可执行文件优先 execFile 避免 shell 注入
跨平台需求避免直接使用 shell 语法