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