中文资讯 掘金 AI Thu, 27 Aug 2026 正文 ok 577 words

execa:Node.js 新一代 child_process 强力替代方案

英文标题:execa NodeJs新一代child_process的强力替代品

execa 是 Node.js 原生 `child_process` 模块的增强替代品,为执行系统命令提供了简单、可靠且对新手友好的 Promise API。它支持直接通过 `await` 获取 `stdout`、`stderr` 和退出码,并提供包含完整上下文的异常对象,减少回调和 Buffer 处理的复杂度。该库通过数组参数与 `$` 模板字符串自动转义机制降低 Shell 注入风险,同时覆盖同步执行、流式输出、管道、超时、取消任务等常见场景。对于需要在 Node.js 脚本、构建工具、CLI 或自动化流程中调用外部命令的开发者,execa 提供了比原生 API 更易用的封装。
打开原文相关 2 · 机会 2
media3.2 KB media589 B media10.1 KB

中文

execa

execa 是 Node.js 官方 child_process 模块的增强替代品。它将 JavaScript 中较为繁琐的“执行命令”操作,封装为简单、可靠、对新手友好的 Promise API。

与原生写法相比,优势明显:

执行并获取输出 需要自行封装 Promise 可直接 await,返回 {stdout, stderr}
捕获错误 需要判断回调中的 error 对象 直接使用 catch,错误对象信息完整
二进制输出 Buffer 处理繁琐 stdout 自动按 UTF-8 解码为字符串

快速开始:

npm install execa

import { execa } from 'execa'

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

try{
    await execa('unknown-command');
} catch(error){
  console.log(error.shortMessage);
  
  console.log(error.exitCode); 
}

await 会返回 {stdout, stderr};无论命令成功或失败,都可以获取对应的返回结果与错误信息。

核心 API

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

这是最常用的形式。通过数组传参,无需拼接字符串,可天然规避 Shell 注入风险:

await execa('git', ['log', '--oneline', '-5']);

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

虽然 execa 的底层参数形式为数组,但它提供了 $ 语法糖,让你能够使用模板字符串,同时自动完成参数转义:

import { $ } from 'execa';

await $`echo hello`;                    
await $`git commit -m ${'feat: 新功能'}`; 

const { stdout } = await $`ls -al`;
execaSync('command',[arguments],[options])

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

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 — 包含命令、参数和退出码
  • 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

加载配置与默认值:

const res = await execa('node', ['app.js'], {
  cwd: path.resolve('./server'),
  timeout: 10000,
  env: { NODE_ENV: ' 'production' },
});

进阶能力

1. 管道(stream 链式)
import { execa } from 'execa';

const psResult = await execa('ps', ['aux'], { stripFinalNewline: false });
await execa('grep', ['node'], { input: psResult.stdout });
2. 流式实时输出(实时看到命令逐行输出,而非最后一次性返回)
const subprocess = execa('npm', ['run', 'build'], { buffering: false });
subprocess.stdout.pipe(process.stdout);     
subprocess.stderr.pipe(process.stderr);

subprocess.catch((error) => {
  console.error(error.stderr);
});
3. 取消任务(kill / cancel)
const subprocess = execa('node', ['long-task.js']);
setTimeout(() => subprocess.kill('SIGTERM'), 3000);

await subprocess; 

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

如果不希望失败时抛出异常,只想根据退出码进行判断:

const result = await execa('my-tool', args, { reject: false });
console.log(result.exitCode, result.failed, result.stderr);
6. 执行完整 Shell 脚本
const { stdout } = await execa('bash', ['-c', 'echo a && echo b']);

English / 原文

execa

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

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

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

快速开始:

npm install execa



import { execa } from 'execa'

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

try{
    await execa('unknown-command');
} catch(error){
  console.log(error.shortMessage);
  
  console.log(error.exitCode); 
}

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

核心API

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

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

await execa('git', ['log', '--oneline', '-5']);


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

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

import { $ } from 'execa';

await $`echo hello`;                    
await $`git commit -m ${'feat: 新功能'}`; 


const { stdout } = await $`ls -al`;
execaSync('command',[arguments],[options])

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

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

加载配置与默认值 :

const res = await execa('node', ['app.js'], {
  cwd: path.resolve('./server'),
  timeout: 10000,
  env: { NODE_ENV: ' 'production' },
});

进阶能力

1 管道(stream 链式)
import { execa } from 'execa';

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


subprocess.catch((error) => {
  console.error(error.stderr);
});
3 取消任务(kill / cancel)
const subprocess = execa('node', ['long-task.js']);
setTimeout(() => subprocess.kill('SIGTERM'), 3000);

await subprocess; 


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

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

const result = await execa('my-tool', args, { reject: false });
console.log(result.exitCode, result.failed, result.stderr);
6 执行 shell 整段脚本
const { stdout } = await execa('bash', ['-c', 'echo a && echo b']);