Nodejs 命令行调用 exec 与 spawn 差异
比如在前端工程项目中 Nodejs 要调用命令行命令如:
yarn electron:build
exec 调用 yarn 命令,为了能使命令行能实时打印输出正在编译的命令
以异步形式调用 exec 使用 stdout.on 方式监听标准输出,并打印
// 打包 electron const buildElectron = () => { return new Promise((resolve, reject)=> { console.log(`yarn electron:build`) const buildExec = exec(`yarn electron:build`, (error, stdout, stderr) => { if (error) { console.error(`exec error: ${error}`); reject() return; } resolve() }); buildExec.stdout.on('data', function(data) { // 此处会实时打印输出 console.log(data.toString()) }); }) } // 启动调用 buildElectron();
对于普通的命令行来说这足够了,但当你的命令行输出内容较大时,exec 命令就不行了
此时需要更换 spawn 命令
const command = spawn('yarn', ['command']);
spawn 使用 child_process 模块的方法,但与 exec 不同的是,命令行的参数需要以数组的形式传递进去:
const { spawn } = require('child_process'); const command = spawn('yarn', ['command']); command.stdout.on('data', (data) => { console.log(`stdout: ${data}`); }); command.stderr.on('data', (data) => { console.error(`stderr: ${data}`); }); command.on('close', (code) => { console.log(`child process exited with code ${code}`); });
然后就在我的 PC 电脑上报错了
spawn yarn enoent
问一下 chatgpt 这是啥错误:
大至意思是 spawn 命令在执行时找不到 yarn 命令, 执行命令时需要带上具体路径
spawn('C:\Program Files\nodejs\yarn', ['command']);
按以上提示后运行以命令
还是报错
继续问 chatgpt
然后答案是,需要用 yarn.cmd 如下:
const { spawn } = require('child_process'); const command = spawn('C:\\Program Files\\nodejs\\yarn.cmd', ['command']);
写死路径,太不科学了,如果其它前端小伙伴接取代码行动的话说不定会报错。。。
最后发现直接用 yarm.cmd 即可,不用完整路径
const { spawn } = require('child_process'); const command = spawn('yarn.cmd', ['command']);
问题又解决了
还有如果你用的是 pnpm , 解决 spawn pnpm ENOENT error 也是一样的处理方法
const { spawn } = require('child_process'); const command = spawn('pnpm.cmd', ['command']);
两者不同
- 输入输出处理:
- spawn: 提供了输入输出的流式接口。它返回了一个 ChildProcess 对象允许你流式读写
- exec: 整个输出都存到了 buffers 缓冲区,然后传递给回调。它使用起来虽然比较简单,但当命令输出的结果太大时就可能出错。
- 指令执行
- spawn: 使用新的进程启动命令行,允许独立运行。它允许长时间运行或可执行继续交互命令
- exec: 命令在 shell 中执行,输出结果在缓存区。它使用方便,但输出复杂结果是会有问题或无法在未中断命令的情况下继续进行交互命令
- Shell 使用:
- spawn: 默认不使用 Shell. 参数需要数组方式传递.
- exec: 使用 Shell. 允许你使用 Shell 的一些特征 pipes, input/output 重定向, 和命令的置换.
- 错误处理:
- spawn: 在 ChildProcess 对象上发送错误事件。可以监听并处理它
- exec: 错误通过回调内第一个参数传递。可以据此处理