「学习笔记」child_process

小越越 -
「学习笔记」child_process
child_process

child_process 用于创建衍生子进程。Node 和衍生的子进程建立 stdin(标准输入), stdout(标准输出), stderr(标准错误) 管道。child_process.spawn, child_process.fork, child_process.exec, child_process.execFile 都会返回 ChildProcess 实例。ChildProcess 实例实现了 EventEmitter API,可以在子进程实例上添加事件的回调函数。进程之间可以通过事件消息系统进行互相通信。

child_process.spawn

启动一个子进程,执行命令。spawn 的接口定义: spawn(command: string, args: ReadonlyArray<string>, options: SpawnOptions): ChildProcess

command, 需要运行的命令args, 运行命令的参数, 是一个字符串数组

options, 配置项

options.cwd 子进程的工作目录options.env 环境变量, 使用 key, value 配置环境变量等等返回值 ChildProcess, 返回 ChildProcess 的实例
// 例子
const { spawn, spawnSync } = require('child_process')
const path = require('path')

const cp = spawn('ls', ['-a'], {
  cwd: path.resolve(__dirname, '../Movies')
})

cp.stdout.on('data', (data) => {
  console.log(`子进程输出:' ${data}`)
})

cp.on('exit', (code, signal) => {
  console.log('子进程退出:', `code ${code} and signal ${signal}`)
})

输出结果:

child_process.spawn1.png

默认情况下,子进程的标准输入、标准输出和标准错误被重定向到 ChildProcess 对象上相应的 subprocess.stdin, subprocess.stdout 和 subprocess.stderr 流。可以设置 options.stdio: inherit, 传入父进程,

const { spawn, spawnSync } = require('child_process')
const path = require('path')

const cp = spawn('ls', ['-a'], {
  cwd: path.resolve(__dirname, '../Movies'),
  stdio: 'inherit'
})
child_process.spawnSyncchild_process.spawn 的同步版本。child_process.spawnSync 返回 Object。Object 包含了: pid(子进程pid), stdout(标准输出), stderr(标准错误) 等等。不同之处在于该函数在子进程完全关闭之前不会返回。
const { spawnSync } = require('child_process')
const path = require('path')


const obj = spawnSync('ls', ['-a'],{ cwd: path.resolve(__dirname, '../Movies') })

console.log('pid', `${obj.pid}`)
console.log('stdout', `${obj.stdout}`)
child_process.exec

创建一个衍生的 shell, 然后可以在衍生的 shell 之中执行命令。exec 实现了函数重载。第二个参数可以是配置项,或者是 callback。如果第二个参数是配置项,那么第三个参数就是 callback。

const { exec } = require('child_process')
const path = require('path')

exec('ls', (error, stdout, stderr) => {
  if (error) {
    console.error('error:', error);
    return;
  }
  console.log('stdout: ' + stdout);
  console.log('stderr: ' + stderr);
})

// 第二个参数可以是配置项
exec('ls -a', { cwd: path.resolve(__dirname, '../Movies'), }, (error, stdout, stderr) => {
  if (error) {
    console.error('error:', error);
    return;
  }
  console.log('stdout: ' + stdout);
  console.log('stderr: ' + stderr);
})

callback 的三个参数分别是错误实例(如果执行成功, error 等于 null), stdout 标准输出, stderr 标准错误。

child_process.execSyncchild_process.exec 的同步版本。child_process.execSync 方法返回标准输出,不同之处在于该方法在子进程完全关闭之前不会返回。
const { execSync } = require('child_process')
const path = require('path')

const stdout = execSync('ls -a', { cwd: path.resolve(__dirname, '../Movies') })

console.log('stdout:', `${stdout}`)
child_process.exec 和 child_process.spawn 区别

spawn

不会创建衍生的 shell流式的传输子进程产生的数据没有数据大小的限制

exec

会创建衍生的 shell最大传输 200kb 的数据会缓存数据, 进程关闭后传输数据

spawn 适合巨大长时间的传输数据。exec 适合需要多次,小量的情况。

child_process.fork

child_process.fork, 用于在子进程中运行模块。child_process.fork(modulePath [, args] [, options])

modulePath, 需要在子进程中运行的模块地址args, 字符串参数列表

options 配置项

execPath, 用来创建子进程的可执行文件。我们可以通过配置这个参数,指定不同版本的 node 创建子进程。execArgv, 传给可执行文件的字符串参数列表。silent, 子进程的标准输出, 是否从父进程进行继承。默认是 false 进行继承。如果设置为 true 则直接 pipe 向子进程的 child.stdin, child.stdout 等。stdio, 用于配置在父进程和子进程之间建立的管道
// 子进程的代码
console.log('我是子进程')
const { fork } = require('child_process')
const { resolve } = require('path')

// 我是子进程
fork(resolve(__dirname, './cp.js'), {
  silent: false
})

// 没有打印
fork(resolve(__dirname, './cp.js'), {
  silent: true
})
const { fork } = require('child_process')
const { resolve } = require('path')

const cp = fork(resolve(__dirname, './cp.js'), {
  silent: true
})

cp.stdout.on('data', function (data) {
  // stdout 中输出: 我是子进程
  console.log('stdout 中输出:', `${data}`)
})

通过 stdout 属性,可以获取到子进程输出的内容

child_process.execFile

child_process.execFile 不会创建衍生的 shell。效率要比 exec 要高。child_process.execFile(file[, args] [, options] [, callback])

file, 可以是执行文件的名字,或者路径。
const { execFile } = require('child_process')
const { resolve } = require('path')

execFile('node', [resolve(__dirname, './cp.js')], (err, stdout, stderr) => {
  if (err) {
    throw err
  }
  console.log(`stdout: ${stdout}`)
})
child_process.exec 和 child_process.execFile 的区别

exec 内部通过调用 execFile 来实现。而 execFile 内部通过调用 spawn 来实现。

事件

ChildProcess 实例上可以监听很多事件

close, 子进程的 stdio 流关闭时触发disconnect, 父进程手动调用 child.disconnect 函数时触发error, 产生错误时会触发exit, 子进程退出时触发message, 子进程使用 process.send 函数来传递消息时触发
const { fork } = require('child_process');

const cp = fork('./cp.js')

cp.on('close', (code, signal) => {
  console.log('close 事件:', code, signal);
})

cp.on('disconnect', () => {
  console.log('disconnect 事件...');
})

cp.on('error', (code, signal) => {
  console.log('error 事件:', code, signal);
})

cp.on('exit', (code, signal) => {
  console.log('exit 事件:', code, signal);
})

cp.on('message', (val) => {
  console.log('message 事件:', val);
})
进程之间的通信

创建子进程后, 父进程与子进程之间将会创建 IPC 通道,父子进程之间通过 message 和 send 来通信。

// 父进程
const { fork } = require('child_process');

const cp = fork('./cp.js')

cp.on('message', (msg) => {
  console.log('message: ' + JSON.stringify(msg))
})
// 子进程
process.send({
  msg: '我是子进程'
})

父进程也可以向子进程发送消息使用 cp.send

// 父进程
const { fork } = require('child_process');

const cp = fork('./cp.js')

cp.send({
  msg: '我是父进程'
})
参考Node.js v16.8.0 文档Node.js Child Processes: Everything you need to knowexec vs execFile nodeJsNode.js Spawn vs. ExecuteNodejs进阶:如何玩转子进程(child_process)深入理解Node.js 中的进程与线程Node.js process 模块学习指南玩转 node 子进程 — child_process
特别申明:本文内容来源网络,版权归原作者所有,如有侵权请立即与我们联系(cy198701067573@163.com),我们将及时处理。

Tags 标签

前端javascriptnode.js

扩展阅读

加个好友,技术交流

1628738909466805.jpg