← 中文资源

简体中文版本

Execa 异步子进程与干净输出

用 execa 执行子进程:参数走数组避免注入、stdout 与 stderr 分离解析、非零退出码转为可判断的失败结果。

阅读英文原文

示例说明

原生 child_process 的回调与流式输出拼接繁琐,且容易把参数拼进 shell 字符串造成注入。execa 把子进程封装成 Promise,参数以数组传递不走 shell,stdout 与 stderr 分开返回,退出码与失败原因也成为结构化字段,适合在 CLI 工具或脚本管线里组合调用。

技术要点

  • 参数数组形式天然避免 shell 注入风险
  • reject:false 把失败转为普通返回值便于分支处理
  • timeout 选项为子进程提供硬性时间上限

代码解读

runChecks 里执行 git diff –stat 并指定工作目录;reject 设为 false 后命令失败不会抛异常,而是返回带 failed 与 exitCode 字段的结果对象,代码据此打印 stderr 并返回布尔值。第二段演示 timeout 选项,超时会让进程被终止并抛出超时错误。

使用建议

需要 shell 特性(管道、通配符)时可显式开启 shell 选项,但输入来自外部时务必避免。长输出应改用 execa 的流式接口逐块消费,防止整段缓存占用过多内存。退出码语义要与服务约定对齐。

代码示例

import { execa } from 'execa';

async function runChecks() {
  const result = await execa('git', ['diff', '--stat'], {
    cwd: process.cwd(),
    reject: false,
  });

  if (result.failed) {
    console.error('command failed with code', result.exitCode);
    console.error(result.stderr.trim());
    return false;
  }
  console.log(result.stdout.trim());
  return true;
}

const timeout = await execa('node', ['--version'], { timeout: 5000 });
console.log('node version:', timeout.stdout.trim());