[Node.js] child_process

child_process是node中的一个内置模块,
它提供了衍生(spawn)子进程的功能。

1. fork 示例

index.js

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

console.log('1. start fork');
const child = fork('./child.js');

console.log('2. start on message');
child.on('message', data => {
  console.log(`9. end message: ${data.y}`);
});

console.log('3. start send');
child.send({ x: 1 });
console.log('4. end send');

child.js

console.log('5. in child - start message');
process.on('message', data => {
  console.log(`6. in child - end message: ${data.x}`);

  console.log('7. in child - start send');
  process.send({ y: 2 });
  console.log('8. in child - end send');
});

则日志信息如下,

$ node index.js
1. start fork
2. start on message
3. start send
4. end send
5. in child - start message
6. in child - end message: 1
7. in child - start send
8. in child - end send
9. end message: 2
(挂住)

fork会建立一个永久的channel,以供进程间通信。
因此,以上日志打印完后,会挂住。

可以使用child.disconnect()关闭这个通道。

child.on('message', function () {
    console.log('9. end message');

    // 关闭channel
    child.disconnect();
});

2. spawn 示例

child_process.spawn() 方法使用给定的 commandargs 中的命令行参数来衍生一个新进程。
如果省略 args,则默认为一个空数组。

2.1 调用shell命令

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

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

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

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

它会执行命令行操作,

$ ls -lh /usr

2.2 利用 stdin 和 stdout 与子进程通信

index.js

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

console.log('1. start spawn');
const child = spawn('node', ['./child.js']);

console.log('2. start stdout on data');
child.stdout.on('data', data => {
  // 子进程 console.log 也会触发,使用随机数区分
  console.log(`${Math.random()}: stdout on data - ${data}`);
});

console.log('3. start child on close');
child.on('close', code => {
  console.log(`12. child on close: ${code}`);
});

console.log('4. child stdin write');
child.stdin.write('[x]');
console.log('5. child stdin end write');

child.js

console.log('6. in child - start process stdin on data');

process.stdin.on('data', data => {
  console.log(`7. child stdin on data: ${data}`);

  console.log('8. child process stdout write');

  // 与 console.log 效果一样,只是不带末尾换行符
  process.stdout.write('[y]');
  console.log('9. child process stdout end write');

  console.log('10. child process exit');
  process.exit(1);
  console.log('11. child process end exit');  // 不触发
});

日志信息如下,

$ node index.js
1. start spawn
2. start stdout on data
3. start child on close
4. child stdin write
5. child stdin end write
0.5171850730160528: stdout on data - 6. in child - start process stdin on data

0.4755742447483853: stdout on data - 7. child stdin on data: [x]

0.02516364602172283: stdout on data - 8. child process stdout write
[y]9. child process stdout end write
10. child process exit

12. child on close: 1

注:
(1)子进程的 console.log 也会触发子进程的 stdout 回调,
因此,这里写了一个随机数,以标识不同的触发。

child.stdout.on('data', data => {
  // 子进程 console.log 也会触发,使用随机数区分
  console.log(`${Math.random()}: stdout on data - ${data}`);
});

(2)process.exit(1);调用后,子进程立即结束,
因此后续的 console.log没有触发。

console.log('11. child process end exit');  // 不触发

(3)spawn后,子进程就启动了,只不过启动是异步的,
落后于主进程的 child.stdin.write('[x]');

保持 child.js 不变, 修改 index.js,

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

console.log('1. start spawn');
const child = spawn('node', ['./child.js']);

console.log('2. start stdout on data');
child.stdout.on('data', data => {
  console.log(`${Math.random()}: stdout on data - ${data}`);
});

则日志信息如下,

node index.js
1. start spawn
2. start stdout on data
0.9460758839302479: stdout on data - 6. in child - start process stdin on data
(挂住)

(4)子进程中的 process.stdout.write('[y]'); 效果与conosle.log相同,
只是末尾不带换行符,参考日志,

[y]9. child process stdout end write

3. 其他

  1. child_process.exec(): 衍生一个 shell 并在 shell 上运行命令,当完成时会传入 stdout 和 stderr 到回调函数。
  2. child_process.execFile(): 类似 child_process.exec(),但直接衍生命令,且无需先衍生 shell。
  3. child_process.fork(): 衍生一个新的 Node.js 进程,并通过建立 IPC 通讯通道来调用指定的模块,该通道允许父进程与子进程之间相互发送信息。
  4. child_process.execSync(): child_process.exec() 的同步函数,会阻塞 Node.js 事件循环。
  5. child_process.execFileSync(): child_process.execFile() 的同步函数,会阻塞 Node.js 事件循环。

参考

node v8.12.0 docs: child_process
node v10.12.0 中文文档:子进程

你可能感兴趣的:([Node.js] child_process)