Skip to main content

创建一个进程 (Bun.spawn())

提供一个字符串数组作为命令。Bun.spawn() 返回一个 Bun.Subprocess 对象。
Bun.spawn 的第二个参数是一个用于配置子进程的参数对象。

输入流

默认情况下,子进程的输入流未定义;请使用 stdin 参数进行配置。
使用 "pipe" 时,父进程可以向子进程的输入流增量写入数据。
将 ReadableStream 传递给 stdin 时,它会将数据直接通过管道传输到子进程的输入流:

输出流

从 stdout 和 stderr 属性读取子进程的输出。默认情况下,stdout 是 ReadableStream 的一个实例;stderr 继承自父进程,因此 proc.stderr 为 undefined。传入 stderr: "pipe",也可以为它获取一个 ReadableStream。
通过向 stdout/stderr 传入以下值之一来配置输出流:

退出处理

使用 onExit 回调监听进程退出或被杀死。
index.ts
exited 属性是一个 Promise,在进程退出时解析。
index.ts
杀死进程:
index.ts
父 bun 进程不会终止,直到所有子进程都已退出。使用 proc.unref() 将子进程与父进程分离。
index.ts

资源使用

进程退出后,resourceUsage() 会报告其资源使用情况:
index.ts

使用 cgroups 限制资源(Linux)

在 Linux 上,传入 cgroup 可在控制组内启动子进程。子进程会在开始执行前加入 cgroup,因此在 cgroup 上配置的限制(内存、pids、CPU)从第一条指令起就会生效。这些限制也适用于子进程随后启动的每个进程。超过内存限制时,内核会在 cgroup 内部对进程执行 OOM 终止,而不是从父进程回收内存。 cgroup 是 /sys/fs/cgroup 下的一个目录;使用普通文件操作创建并配置它,然后传入其路径(或已打开的目录文件描述符):
index.ts
可以将同一个目录传递给任意数量的 spawn;限制会应用于它们的总用量。Bun 同时支持 cgroup v1 和 v2 层级结构。创建 cgroup 通常需要 root 权限或一个已委派的子树。在其他平台上,Bun 会忽略此选项;在 Linux 上,如果子进程无法加入 cgroup,spawn 就会失败。

使用 AbortSignal

你可以使用 AbortSignal 中止子进程:
index.ts

使用 timeout 和 killSignal

将 timeout 设置为在经过指定的毫秒数后终止子进程:
index.ts
默认情况下,Bun 会使用 SIGTERM 终止超时的进程。使用 killSignal 选项指定其他信号:
index.ts
killSignal 选项也控制当 AbortSignal 中止时 Bun 发送的信号。

使用 maxBuffer

对于 Bun.spawnSync,maxBuffer 限制进程在 Bun 将其终止前可以输出的字节数:
index.ts
一旦超过限制,Bun 就会停止读取。因此,返回的输出最多只会因那次超过限制的读取而超出 maxBuffer,不会超过进程在终止生效前设法写入的任何额外内容。这与 Node.js 的行为一致。

进程间通信(IPC)

Bun 支持两个 bun 进程之间的直接进程间通信通道。要接收由 Bun 子进程发送的消息,请指定一个 ipc 处理器。
parent.ts
父进程通过返回的 Subprocess 实例上的 .send() 方法向子进程发送消息。ipc 处理器还会将发送消息的子进程作为第二个参数接收。
parent.ts
子进程使用 process.send() 向父进程发送消息,并通过 process.on("message") 接收消息。Node.js 在 child_process.fork() 中使用相同的 API。
child.ts
child.ts
serialization 选项控制两个进程间通信的序列化格式:
  • advanced:(默认)Bun 使用 JSC serialize API 序列化消息,该 API 支持克隆 structuredClone 支持的所有内容。此格式不支持转移对象的所有权。
  • json:Bun 使用 JSON.stringify 和 JSON.parse 序列化消息,相比 advanced,它支持的对象类型较少。
断开与父进程的 IPC 通道可调用:

Bun 与 Node.js 之间的 IPC

要在 bun 和 Node.js 进程间使用 IPC,请在 Bun.spawn 中设置 serialization: "json"。这是因为 Node.js 和 Bun 使用不同的 JS 引擎及不同的对象序列化格式。
bun-node-ipc.js

终端(PTY)支持

对于交互式终端应用,使用 terminal 选项启动附加伪终端(PTY)的子进程。子进程会看到一个真实终端,从而支持彩色输出、光标移动和交互式提示。
传入 terminal 选项时:
  • 子进程中 process.stdout.isTTY 为 true
  • stdin、stdout 和 stderr 都绑定到终端
  • proc.stdin、proc.stdout 和 proc.stderr 返回 null —— 使用终端对象代替
  • 可通过 proc.terminal 访问终端

终端选项

终端方法

proc.terminal 返回的 Terminal 对象具有以下方法:

可复用终端

要通过同一个终端会话按顺序运行多个命令,可以独立创建终端,并在多个子进程之间复用:
传入已有的 Terminal 对象时:
  • 可以在多个 spawn 之间复用终端
  • 可以自行控制何时关闭终端
  • exit 回调会在调用 terminal.close() 时触发,而不是在每个子进程退出时触发
  • 使用 proc.exited 检测各个子进程的退出状态

平台差异

Bun.Terminal 在 Linux 和 macOS 上使用 openpty(),在 Windows 上使用 ConPTY(CreatePseudoConsole)。所有平台上的核心行为都相同:子进程会看到一个 TTY,write() 会将数据写入子进程的 stdin,子进程输出会传递给 data 回调,resize() 会更新子进程看到的终端视图。部分细节有所不同:
  • Windows 上没有 termios。 inputFlags、outputFlags、localFlags 和 controlFlags 始终读取为 0,设置这些值也不会产生效果。setRawMode() 会记录该标志,但不会影响子进程;子进程会自行控制其控制台模式。
  • Windows 上没有子进程时不会回显。 在 POSIX 上,即使没有附加进程,内核行规程也会将 write() 输入回显到 data 回调。ConPTY 没有行规程;它会缓冲输入,等待下一个读取方。如果需要回显,请启动一个会回显输入的进程。
  • ConPTY 会重新编码输出。 ConPTY 会将子进程的输出渲染到虚拟屏幕,并发出描述渲染结果的 VT 序列。因此,data 回调接收的转义序列在语义上等效,但字节内容不完全相同。ConPTY 会保留颜色和文本,但可能会重新排序或合并光标定位和重置序列。在任何子进程输出之前,ConPTY 还会发出一段简短的 VT 初始化序列(\x1b[?9001h\x1b[?1004h…)。
  • Windows 上的输入 \r 不会转换为 \n。 POSIX 的 ICRNL 会在输入时将回车映射为换行;ConPTY 则会原样传递 \r。
  • 在 ConPTY 下,子进程中的 process.on('SIGWINCH') 不会触发,除非子进程以原生模式读取 stdin。调用 resize() 后,process.stdout.columns/rows 会更新。缺少此信号是 libuv 的限制,影响所有基于 libuv 的子进程(包括 Node.js)。
  • 在 Windows 11 24H2(内部版本 26100)之前,terminal.close() 可能无法及时终止仍在运行的子进程。延迟来自 ClosePseudoConsole:在这些版本中,它会阻塞,直到 conhost 将输出刷新到管道中。如果需要在子进程仍运行时拆除终端,请先杀死附加的进程。
  • Windows 10 或 Windows Server 2019 上的鼠标跟踪不起作用。 这些版本中内置的 ConPTY(conhost 内部版本 17763 至 19045)早于 microsoft/terminal#4856,会丢弃子进程写入的鼠标跟踪启用序列(\x1b[?1000h、\x1b[?1002h、\x1b[?1006h)。这些序列永远不会到达 data 回调,因此外部终端不会报告鼠标事件,子进程也不会收到鼠标事件。Windows 11 和 Server 2022 会转发这些序列,但只有在子进程写入这些序列前启用了 VT 输入模式(例如使用 process.stdin.setRawMode(true))时才会转发。

阻塞式 API (Bun.spawnSync())

Bun.spawnSync 是 Bun.spawn 的阻塞式等价 API。它支持相同的输入和参数,并返回一个 SyncSubprocess 对象,该对象在几个方面不同于 Subprocess。
  1. 返回的对象包含一个 success 属性,用于指示进程是否以零退出码退出。
  2. stdout 和 stderr 属性是 Buffer 的实例,而不是 ReadableStream。
  3. 没有 stdin 属性。使用 Bun.spawn 可向子进程的输入流增量写入数据。
原则上,异步的 Bun.spawn 适合 HTTP 服务器和应用,Bun.spawnSync 更适合构建命令行工具。

性能基准

⚡️ Bun.spawn 和 Bun.spawnSync 使用 posix_spawn(3)。
Bun 的 spawnSync 比 Node.js 的 child_process 模块快 60%。
terminal
terminal

参考

以下是 Spawn API 和类型的参考。实际类型包含复杂的泛型,用于根据传递给 Bun.spawn 和 Bun.spawnSync 的选项,对 Subprocess 流进行强类型约束。完整详情请参阅 bun.d.ts。
查看可展开的 TypeScript 定义