child_process模块提供了和popen(3)一样的方式来产生自进程,这个功能主要是通过child_process.spawn函数来提供的:
const spawn = require('child_process').spawn; const ls = spawn('ls', ['-lh', '/usr']); ls.stdout.on('data', (data) => { console.log(`stdout: ${data}`); }); ls.stderr.on('data', (data) => { console.log(`stderr: ${data}`); }); ls.on('close', (code) => { console.log(`child process exited with code $[code]`); });
默认情况下,Node.js进程和子进程之间的stdin,stdout,stderr管道是已经存在的。通常情况下这个方法可以以一种非阻塞的方式来传递数据。(注意,有些程序在内部使用line-buffered I/O。因为这也不会影响到Node.js,这意味着传递给子进程的数据可能不会马上消费)。
chid-process的spawn方法是通过一种异步的方式来产生自进程的,因此不会阻塞Node.js的事件循环,然而child-process.spawnSync方法是同步的,他会阻塞事件循环只到产生的进程退出或者终止。
child_process.exec:产生一个shell客户端,然后使用shell来执行程序,当完成的时候传递给回调函数一个stdout和stderr
child_process.execFile:和exec相似,但是他不会马上产生一个shell
child_process.fork:产生一个新的Node.js进程,同时执行一个特定的模块来产生IPC通道,进而在父进程和子进程之间传输数据
child_process.execSync:和exec不同之处在于会阻塞Node.js的事件循环,然而child-process
child_process.execFileSync:和execFile不同之处在于会阻塞Node.js的事件循环,然而child-process在一些特殊情况下,例如自动化shell脚本,同步的方法可能更加有用。多数情况下,同步的方法会对性能产生重要的影响,因为他会阻塞事件循环
child_process.spawn(), child_process.fork(), child_process.exec(), and child_process.execFile()都是异步的API。每一个方法都会产生一个ChildProcess实例,而且这个对象实现了Node.js的EventEmitter这个API,于是父进程可以注册监听函数,在子进程的特定事件触发的时候被调用。 child_process.exec() 和 child_process.execFile()可以指定一个可选的callback函数,这个函数在子进程终止的时候被调用。
在windows平台上执行.bat和.cmd:
child_process.exec和child_process.execFile的不同之处可能随着平台不同而有差异。在Unit/Linux/OSX平台上execFile更加高效,因为他不会产生shell。在windows上,.bat/.cmd在没有终端的情况下是无法执行的,因此就无法使用execFile(child_process.spawn也无法使用)。在window上,.bat/.cmd可以使用spawn方法,同时指定一个shell选项;或者使用child_process.exec或者通过产生一个cmd.exe同时把.bat/.cmd文件传递给它作为参数(child_process.exec就是这么做的)。
const spawn = require('child_process').spawn; const bat = spawn('cmd.exe', ['/c', 'my.bat']);//使用shell方法指定一个shell选项 bat.stdout.on('data', (data) => { console.log(data); }); bat.stderr.on('data', (data) => { console.log(data); }); bat.on('exit', (code) => { console.log(`Child exited with code $[code]`); });
或者也可以使用如下的方式:
const exec = require('child_process').exec;//产生exec,同时传入.bat文件 exec('my.bat', (err, stdout, stderr) => { if (err) { console.error(err); return; } console.log(stdout); });
child_process.exec(command[, options][, callback])
其中options中的maxBuffer参数表示stdout/stderr允许的最大的数据量,如果超过了数据量那么子进程就会被杀死,默认是200*1024比特;killSignal默认是'SIGTERM'。其中回调函数当进程结束时候调用,参数分别为error,stdout,stderr。这个方法返回的是一个ChildProcess对象。
const exec = require('child_process').exec; const child = exec('cat *.js bad_file | wc -l', (error, stdout, stderr) => { console.log(`stdout: ${stdout}`); console.log(`stderr: ${stderr}`); if (error !== null) { console.log(`exec error: ${error}`); } });
上面的代码产生一个shell,然后使用这个shell执行命令,同时对产生的结果进行缓存。其中回调函数中的error.code属性表示子进程的exit code,error.signal表示结束这个进程的信号,任何非0的代码表示出现了错误。默认的options参数值如下:
{ encoding: 'utf8', timeout: 0, maxBuffer: 200*1024,//stdout和stderr允许的最大的比特数据,超过她子进程就会被杀死 killSignal: 'SIGTERM', cwd: null, env: null }
如果timeout非0,那么父进程就会发送信号,这个信号通过killSignal指定,默认是"SIGTERM"来终结子进程,如果子进程超过了timeout指定的时间。注意:和POSIX系统上调用exec方法不一样的是,child_process.exec不会替换当前线程,而是使用一个shell去执行命令
child_process.execFile(file[, args][, options][, callback])