execa NodeJs新一代child_process的强力替代品

execa

execa 是 NodeJs 官方 child_process 模块的增强替代品。把 JS 里"执行命令"这件麻烦事,做成简单、可靠、对新手友好的 Promise API

对比原生写法,优势立现:

操作 child_process 原生 execa
执行并拿输出 要自己包 Promise 直接 await 返回 {stdout, stderr}
捕获错误 判断回调 error 对象 catch 即可,错误对象信息齐全
二进制输出 Buffer 处理繁琐 stdout 自动 UTF-8 解码成字符串

快速开始:

shell 复制代码
npm install execa
js 复制代码
import { execa } from 'execa'

const { stdout } = await execa('echo',['hello world'])
console.log(stdout); //hello world

try{
    await execa('unknown-command');
} catch(error){
  console.log(error.shortMessage);
  // 命令不存在时:'/bin/sh: unknown-command: command not found'
  console.log(error.exitCode); // 127
}

await 返回 {stdout, stderr},正确回调的返回结果和错误结果。

核心API

execa('command',[argument],[options])

最常用形式,数组传参,不需要拼字符串,天然规避 shell 注入:

js 复制代码
// 执行 git log --oneline -5
await execa('git', ['log', '--oneline', '-5']);

// 传环境变量
await execa('echo', ['$HOME'], { shell: true });
$模板字符串命令

虽然 execa 全程只认数组参数,但提供 $ 语法糖让你写模板字符串,同时自动做参数转义:

js 复制代码
import { $ } from 'execa';

await $`echo hello`;                    // 简单命令
await $`git commit -m ${'feat: 新功能'}`; // 参数自动安全转义,防注入

// 同样返回 { stdout, stderr }
const { stdout } = await $`ls -al`;
execaSync('command',[arguments],[options])

同步版本,适合脚本初始化和简单场景:

js 复制代码
import { execaSync } from 'execa';

const { stdout } = execaSync('npm', ['--version']);
console.log(stdout);

结果对象

await 后返回的对象包含:

  • stdout --- 标准输出字符串
  • stderr --- 错误输出字符串
  • exitCode --- 退出码
  • failed --- 布尔值,是否失败
  • command --- 实际执行的完整命令(便于日志)
  • timedOut、killed、isCanceled 等状态标记

execa 的异常对象非常全(继承 Error):

  • error.stdout / error.stderr --- 失败时的输出/错误输出
  • error.exitCode
  • error.message --- 命令+args+退出码
  • error.shortMessage --- 精简错误信息
  • error.failed --- true
  • error.timedOut / error.isCanceled / error.killed --- 各种失败原因标记
  • error.command --- 实际的完整命令串

同步execa返回的是result对象

常用配置项(options)

选项 作用 示例
cwd 指定工作目录 { cwd: '/path/to/project' }
env 注入环境变量(默认继承父进程) { env: { FOO: 'bar' } }
shell 用 shell 执行(支持管道、重定向、通配符) { shell: true }
timeout 超时强杀(毫秒) { timeout: 5000 }
input 给子进程喂 stdin 数据 { input: 'hello stdin' }
stdio 控制输入输出流向 { stdio: 'inherit' } 可直接打印到终端
reject 失败是否抛错,false 时不抛、返回结果对象 { reject: false }
buffering 关闭输出缓冲、实时流式读取(v7+) { buffering: false } 配合 stream.pipe()/catch()
windowsHide Windows 下隐藏子进程窗口 默认 true

加载配置与默认值:

js 复制代码
// cwd 是高频需求,配合 path 使用
const res = await execa('node', ['app.js'], {
  cwd: path.resolve('./server'),
  timeout: 10000,
  env: { NODE_ENV: ' 'production' },
});

进阶能力

1 管道(stream 链式)
js 复制代码
import { execa } from 'execa';

const psResult = await execa('ps', ['aux'], { stripFinalNewline: false });
await execa('grep', ['node'], { input: psResult.stdout });
2 流式实时输出(看到命令一行行打,而不是最后一次性)
js 复制代码
const subprocess = execa('npm', ['run', 'build'], { buffering: false });
subprocess.stdout.pipe(process.stdout);     // 实时打印
subprocess.stderr.pipe(process.stderr);

// 流式错误处理用 catch 而非 try/catch
subprocess.catch((error) => {
  console.error(error.stderr);
});
3 取消任务(kill / cancel)
js 复制代码
const subprocess = execa('node', ['long-task.js']);
setTimeout(() => subprocess.kill('SIGTERM'), 3000);

await subprocess; // 会被拒绝,错误对象带 killed: true

// v8+ 用 AbortController 更干净
import { execa } from 'execa';
const controller = new AbortController();
setTimeout(() => controller.abort(), 3000);
await execa('node', ['long-task.js'], { signal: controller.signal });
4 超时
js 复制代码
try {
  await execa('ping', ['-t', '127.0.0.1'], { timeout: 2000 });
} catch (error) {
  console.log(error.timedOut); // true
}
5 拒绝策略(reject: false)

不想让失败抛异常、只想拿退出码判断时:

js 复制代码
const result = await execa('my-tool', args, { reject: false });
console.log(result.exitCode, result.failed, result.stderr);
// 不会 throw,一切信息都在 result 里
6 执行 shell 整段脚本
js 复制代码
const { stdout } = await execa('bash', ['-c', 'echo a && echo b']);
相关推荐
lerhxx5 小时前
AI 应用如何高效优雅地恢复中断?—— "连接解耦 + 状态持久化"
前端·javascript
mantou1327 小时前
我给 AI Agent 做了个「油猴」:让 Claude Code / Codex 直接用你已登录的浏览器
前端·javascript·后端
默_笙7 小时前
🍕 一个主编、三个工种、两本手册:搭一支 AI 调研队
前端·javascript
CappuccinoRose7 小时前
FormData数据处理
开发语言·前端·javascript·表单数据
飘尘8 小时前
SVG和Canvas,前端里的两支“画笔”,用的时候怎么选择?
前端·javascript·面试
Sand(ContextGate)12 小时前
Python Agent 测试实战:测试与评估,让 Agent 像传统软件一样可交付
前端·javascript·python·microsoft·ai
码艺-Alimjan13 小时前
Tauri 网站To桌面应用实战总结
前端·javascript·vue
liangshanbo121514 小时前
请求拦截器相关面试题
java·前端·javascript
liangshanbo121514 小时前
React面试题:Hooks 为什么不能在分支和循环里面写?
前端·javascript·react.js
西红柿炖牛腩35414 小时前
GLB 转 OBJ/PLY 后体积没变?3D 模型不减面变小靠什么
前端·javascript·3d