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}`)})
输入后果:
默认状况下,子过程的规范输出、规范输入和规范谬误被重定向到 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.spawnSync
child_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.execSync
child_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 know
- exec vs execFile nodeJs
- Node.js Spawn vs. Execute
- Nodejs进阶:如何玩转子过程(child_process)
- 深刻了解Node.js 中的过程与线程
- Node.js process 模块学习指南
- 玩转 node 子过程 — child_process