「学习笔记」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
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.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.forkchild_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.execFilechild_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