Skip to main content

创建进程(Bun.spawn()

以字符串数组的形式提供命令。Bun.spawn() 的结果是一个 Bun.Subprocess 对象。
Bun.spawn 的第二个参数是一个配置子进程的参数对象。

输入流

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

输出流

stdoutstderr 属性读取子进程的输出。默认情况下,它们是 ReadableStream 的实例。
通过向 stdout/stderr 传递以下值之一来配置输出流:

退出处理

使用 onExit 回调监听进程退出或被杀死的事件。
index.ts
exited 属性是一个 Promise,在进程退出时 resolve。
index.ts
要杀死一个进程:
index.ts
bun 进程在所有子进程退出后才会终止。使用 proc.unref() 将子进程与父进程分离。
index.ts

资源使用

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

使用 AbortSignal

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

使用 timeout 和 killSignal

设置 timeout 可以在指定毫秒数后终止子进程:
index.ts
默认情况下,Bun 使用 SIGTERM 杀死超时进程。使用 killSignal 选项指定不同的信号:
index.ts
killSignal 选项还控制在 AbortSignal 被中止时发送的信号。

使用 maxBuffer

对于 Bun.spawnSyncmaxBuffer 限制进程在 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:(默认)消息使用 JSC serialize API 进行序列化,支持克隆 structuredClone 支持的一切。不支持传输对象所有权。
  • json:消息使用 JSON.stringifyJSON.parse 进行序列化,不支持 advanced 那么多对象类型。
要从父进程断开 IPC 通道,请调用:

Bun 与 Node.js 之间的 IPC

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

终端(PTY)支持

对于交互式终端应用程序,请使用 terminal 选项来生成附加了伪终端(PTY)的子进程。子进程会看到一个真正的终端,从而支持彩色输出、光标移动和交互式提示。
当提供 terminal 选项时:
  • 子进程看到 process.stdout.isTTYtrue
  • stdinstdoutstderr 都连接到终端
  • proc.stdinproc.stdoutproc.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。 inputFlagsoutputFlagslocalFlagscontrolFlags 始终读取为 0,设置它们无效。setRawMode() 会记录该标志但对子进程没有效果;子进程控制自己的控制台模式。
  • Windows 上没有子进程时不会回显。 在 POSIX 上,即使没有附加进程,内核的行规程也会将 write() 输入回显到 data 回调。ConPTY 没有行规程;输入会被缓冲等待下一个读取者。如果需要回显,请启动一个会回显的进程。
  • ConPTY 会重新编码输出。 ConPTY 将子进程的输出渲染到虚拟屏幕,并发出描述结果的任何 VT 序列,因此 data 回调接收的转义序列在语义上等价,但字节不一定相同。颜色和文本被保留;光标定位和重置序列可能会被重新排序或合并。ConPTY 还会在任何子进程输出之前发出一个简短的 VT 初始化序列(\x1b[?9001h\x1b[?1004h…)。
  • 在 Windows 上,输入的 \r 不会转换为 \n POSIX ICRNL 会将回车符映射为输入中的换行符;ConPTY 原样传递 \r
  • 在 ConPTY 下,子进程中的 process.on('SIGWINCH') 不会触发,除非子进程以原始模式读取 stdin。process.stdout.columns/rowsresize() 后确实会更新。这是 libuv 的限制,影响所有基于 libuv 的子进程(包括 Node.js)。
  • 在 Windows 11 24H2(内部版本 26100)之前的版本上,terminal.close() 可能不会及时终止仍在运行的子进程,因为在这些版本上 ClosePseudoConsole 会阻塞直到 conhost 将其输出通过管道刷新完毕。如果需要在子进程仍在运行时销毁,请先杀死附加的进程。

阻塞 API(Bun.spawnSync()

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

基准测试

⚡️ Bun.spawnBun.spawnSync 使用 posix_spawn(3)
Bun 的 spawnSync 创建进程的速度比 Node.js child_process 模块快 60%。
terminal
terminal

参考

以下是 Spawn API 和类型的参考。实际类型具有复杂的泛型,可以根据传递给 Bun.spawnBun.spawnSync 的选项强类型化 Subprocess 流。有关完整细节,请参阅 bun.d.ts
查看 TypeScript 定义 可展开