Node.js中使用spawn无法按顺序执行全部多个子进程问题
问题根因
代码执行卡住、最后一个子进程无法触发,由三个核心问题导致:
- 未处理
stdio: 'inherit'场景下的流空值:当给spawn传入stdio: 'inherit'配置时,子进程的标准输入输出会直接继承父进程流,此时子进程实例的stdout、stderr属性值为null。封装函数里无判断直接调用p.stdout.setEncoding()、给p.stdout绑定data监听,会直接抛出TypeError,如果没有对应捕获逻辑,会导致返回的Promise状态异常,后续await永久挂起。 - 缺少子进程错误事件监听:代码仅监听了子进程的
exit事件,没有监听error事件。如果子进程启动失败(比如命令不存在、权限不足、流操作报错),不会触发resolve逻辑,Promise会一直处于pending状态,后续代码永远不会执行。 - 边界参数未做兼容:调用
spawn('ls')时未传入第二个配置参数,虽然JS不会直接抛出语法错误,但容易触发边界判断异常;另外重复执行mkdir newtemp时,同名目录已存在会触发mkdir报错,未做错误捕获时也会中断执行链。
修复方案
调整spawn封装逻辑,补全空值判断、错误监听、参数默认值即可:
const childProcess = require('child_process'); function spawn (cmd, option = {}){ // 给配置参数加默认空对象,兼容无配置传参 return new Promise((resolve, reject)=>{ let p = childProcess.spawn(cmd, option); // 仅在stdout存在(非inherit模式)时设置编码、绑定输出监听 if (p.stdout) { p.stdout.setEncoding('utf-8'); p.stdout.on('data', (data)=>{ console.log(data); }); } // 仅在stderr存在(非inherit模式)时绑定错误输出监听 if (p.stderr) { p.stderr.on('data', (data)=>{ console.log("process id:"+ p.pid + " child ERROR " + data) }); } p.on('exit', (code)=>{ console.log("process id:"+ p.pid + " child EXIT with code " + code) resolve(code); }); // 补全子进程启动错误监听,出错时主动reject避免Promise挂死 p.on('error', (err) => { console.log("process id:"+ p.pid + " child spawn failed " + err) reject(err); }) }) } async function nnmain(){ await spawn('ls'); await spawn('mkdir newtemp', {shell: true}); await spawn('df -h', {shell: true, stdio: 'inherit'}); await spawn('mkdir newtemp2', {shell: true}); // 此处修改目录名避免和已创建的newtemp重名报错,方便验证执行顺序 } nnmain().catch(e=>console.log('main run error:', e));
优化建议
如果不需要依赖shell解析命令,建议遵循spawn规范传参,把命令和参数拆分传入,不需要开启shell: true,性能和安全性更好,示例写法:
spawn('ls', ['-l'])spawn('mkdir', ['newtemp'])spawn('df', ['-h'], {stdio: 'inherit'})
内容的提问来源于stack exchange,提问作者Ryo Matsuzaka
相关产品推荐
相关产品推荐

