exec踩坑及解决方法

之前做的一个cli工具,要求可以将项目打包编译后上传至服务器,一直使用效果很好。今天同事找到我,告诉我项目必须上传两次才能生效,我就很奇怪为什么,经过短暂定位,发现第一次上传的是之前的编译文件。这就引起我的好奇了,明明代码都没有动过怎么会出现这样的情况。遂将同事的项目和之前使用的项目进行编译上传比对,发现同事的项目编译并没有完成,子进程中途异常中断,所以上传的文件是之前编译的旧文件。下图是同事的项目的输出情况:

图片

此时看似项目已经编译完成,事实上并没有,经过一段时间后编译文件才真正覆盖原文件。下图是正确编译后的情况:

图片

输出了编译后的所有文件。明明都是一样的编译流程,为何却出现了不同的结果?经过研究发现是child_process.exec方法导致子进程异常中断引起的,父进程继续执行上传代码,最终导致上传到服务的文件与预期不同。查询node API 发现12版本前的nodeJS,child_process.exec的maxBuffer参数默认为200kb,项目比较复杂的时候,子进程输出流很容易就超出这个最大限制,然后子进程将终止并截断任何输出,这就是问题所在,不过node版本12之后已经将默认值提升为1M,可以适用大部分的情况。

图片

解决方案一:
升级node版本为12+(仅适用1M以下输出流的情况)
解决方案二:

执行exec方法时,参数中设置一个比较大的maxBuffer值(仅适用最大输出流比较明确的情况,而且exec不是用来返回结果数据的,是用来返回结果状态,尽可能不将maxBuffer设置的特别大)

exec(cmd,{maxBuffer: 1024*1024}) // cmd为执行命令

解决方案三:

使用child_process.spawn代替exec方法,spawn方法是没有最大输出限制的,所以可以完美适配需要获取结果数据的场景。spawn的具体使用方法可以去看官方API (https://nodejs.org/api/child_process.html#child_processspawncommand-args-options)

function asyncExec () {  var ls = spawn('cmd',['/c', 'npm', 'run', 'build'])  return new Promise((resolve, reject) => {    ls.stdout.on('data', (data) => {      log(data.toString('utf8'))    })    ls.stderr.on('data', (data) => {      logRed(data.toString('utf8'))    })    ls.on('error', reject)    ls.on('close', resolve)  })}

最终结果:

图片

遇到难题看文档!看文档!看文档!

阅读原文

简介:人生无时不在焚心,无非是文火与武火的区别罢了。给生活留下点痕迹,给自己留下点回忆。欢迎关注微信公众号:焚心小记
(0)
打赏 喜欢就点个赞支持下吧 喜欢就点个赞支持下吧
网站客服
网站客服
内容投稿 侵权处理
分享本页
返回顶部