回调打印后果
正确的代码执行流程
const cp = require('child_process');const path = require('path');const child = cp.exec('ls -al|grep node_modules', function(err, stdout,stderr){ console.log('start------------------'); console.log(err, stdout, stderr); console.log('end------------------');})child.stdout.on('data', (chunk) => { console.log('stdout data =', chunk);});child.stderr.on('data', (err) => { console.log('stderr data =', err );});child.stdin.on('close', ()=>{ console.log('stdin close');});child.stdout.on('close', () => { console.log('stdout close');});child.stderr.on('close', () => { console.log('stderr close');})child.on('exit',(exitCode) => { console.log('exit=', exitCode );})child.on('close',() => { console.log('close!');})
代码执行的打印程序
stdout data = drwxr-xr-x 280 chensi staff 8960 7 21 17:08 node_modulesexit= 0stdin closestderr closestart------------------null drwxr-xr-x 280 chensi staff 8960 7 21 17:08 node_modules end------------------close!stdout close
谬误的代码执行流程
将ls -al|grep node_modules
这个命令批改为谬误的命令去执行,来察看回调的执行后果,ls3333333 -al|grep node_modules
const child = cp.exec('ls3333333 -al|grep node_modules', function(err, stdout,stderr){ console.log('start------------------'); console.log(err, stdout, stderr); console.log('end------------------');})child.stdout.on('data', (chunk) => { console.log('stdout data =', chunk);});child.stderr.on('data', (err) => { console.log('stderr data =', err );});child.stdin.on('close', ()=>{ console.log('stdin close');});child.stdout.on('close', () => { console.log('stdout close');});child.stderr.on('close', () => { console.log('stderr close');})child.on('exit',(exitCode) => { console.log('exit=', exitCode );})child.on('close',() => { console.log('close!');})
stderr data = /bin/sh: ls3333333: command not foundexit= 1stdin closestdout closestart------------------Error: Command failed: ls3333333 -al|grep node_modules/bin/sh: ls3333333: command not found at ChildProcess.exithandler (node:child_process:398:12) at ChildProcess.emit (node:events:539:35) at maybeClose (node:internal/child_process:1092:16) at Socket.<anonymous> (node:internal/child_process:451:11) at Socket.emit (node:events:539:35) at Pipe.<anonymous> (node:net:709:12) { code: 1, killed: false, signal: null, cmd: 'ls3333333 -al|grep node_modules'} /bin/sh: ls3333333: command not foundend------------------close!stderr close
从打印后果能够看出,正确的输入后果和谬误的输入后果,在打印上还是存在差别,为此我钻研了源码,为了看上去不太干燥,我将尽可能的用通俗易懂的形式来进行形容,当然如果感觉还是看源码比拟清晰一点,也能够对照node源码来看,或者看我上两篇文章;我这里应用的是node v12版本;执行原理和目前的node版本没有差异;我手绘了一张回调函数的执行流程图;
解答:
- 为什么打印程序会是这样的后果?
- 谬误的执行打印程序又为何是这样的?
执行流程
形容
- Process执行命令:子过程执行命令是通过
this._hanlde.spawn
办法实现的 - 执行C++的代码后,会返回是否存在异样的一个code码;返回0示意胜利,小于0示意失败;
- 胜利会进到
onStreamRead
办法,这个办法次要是来监听子过程往流填写信息,同时会派发一个data事件;child.stdout.on('data',()=>{})
,child.stderr.on('data',()=>{})
- 当流中的信息填写实现后,认为流曾经完结了。会敞开回调办法
onReadableStreamEnd
,对所有的socket进行播送一个close事件;只有socket能够监听到child.stdout.on(close',()=>{})
,child.stderr.on('close',()=>{})
; - 接下来会进行一系列的敞开操作
- Process会执行敞开流程,回调子过程中的onexit办法,
Process.onexit
,派发一个exit事件,示意子过程曾经执行实现,过程退出;child.on('exit',() => {})
- 最初
Socket all close
所有的Scoket端口都敞开。派发一个close事件,child.on('close',() => {})
;
因为过程是异步执行的所有两条线
Process的过程执行流程
- 执行实现之后就会执行
Process.onexit
敞开过程
流的读取线
- Process过程执行完后,在pipe管道中进行信息的写入;
onStreamRead
,一共三个流,别离是输出流、输入流、谬误流,会循环调用onStreamRead函数,并且emit data事件; - 所有的信息填写实现之后,调用
onReadableStreamEnd
,onReadableStreamEnd 会调用destroy办法进行敞开流程,将以后的pipe和Socket进行敞开,socket敞开当前会调用 emit close事件,所有的socket emit colose事件都会监听到当前,会调用mybeClose; 当mybClose判断所有的Socket(
Socket all close
)所有的流敞开完当前,派发close事件;流读取谬误: 当监听到异样的时候,还会emit err事件,因为流没有读取所有间接敞开,onStreamReadableEnd
总结
data/error/close/exit的区别
- data:主过程读取数据过程中 通过onStreamRead 去派发的data事件。
- error:命令执行失败后发动的回调。
- close:子过程所有的socket通信端口全副敞开之后发动的回调。
- exit:子过程敞开实现后发动的回调。
- stdout close/ stderr close :特定的PIPE读取实现之后执行onReadableStreamEnd敞开Stock是发动的回调。