创建一个进程 (Bun.spawn())
提供一个字符串数组作为命令。Bun.spawn() 返回一个 Bun.Subprocess 对象。
Bun.spawn 的第二个参数是一个用于配置子进程的参数对象。
输入流
默认情况下,子进程的输入流未定义;请使用stdin 参数进行配置。
使用
"pipe" 时,父进程可以向子进程的输入流增量写入数据。
ReadableStream 传递给 stdin 时,它会将数据直接通过管道传输到子进程的输入流:
输出流
从stdout 和 stderr 属性中读取子进程的输出。默认情况下,这些属性是 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,因此配置在其中的限制——内存、pids、CPU——会从第一条指令开始生效,并应用于该子进程随后生成的每个进程。当超过内存限制时,内核会在 cgroup 内部 OOM-kill 一个进程,而不是从父进程回收内存。
cgroup 是 /sys/fs/cgroup 下的一个目录;使用普通文件操作创建并配置它,然后传入其路径(或已打开的目录文件描述符):
index.ts
使用 AbortSignal
你可以使用AbortSignal 中止子进程:
index.ts
使用 timeout 和 killSignal
将timeout 设置为在经过指定的毫秒数后终止子进程:
index.ts
SIGTERM 终止超时的进程。使用 killSignal 选项指定其他信号:
index.ts
killSignal 选项也控制在 AbortSignal 触发时发送的信号。
使用 maxBuffer
对于Bun.spawnSync,maxBuffer 限制进程在 Bun 将其终止前可以输出的字节数:
index.ts
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 的serializeAPI 序列化,支持克隆所有structuredClone支持的类型 ,但不支持对象所有权转移。json:消息使用JSON.stringify和JSON.parse序列化,支持对象类型比advanced少。
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 对象时:
- 终端可跨多个进程复用
- 你负责何时关闭终端
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 还会在任何子进程输出之前发出一段简短的 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 通过管道刷新完其输出。如果需要在子进程仍在运行时拆除终端,请先终止附加的进程。
阻塞式 API (Bun.spawnSync())
Bun.spawnSync 是 Bun.spawn 的阻塞式等价 API。它支持相同的输入和参数,并返回一个 SyncSubprocess 对象,该对象在几个方面不同于 Subprocess。
- 含有表示进程是否以零退出码退出的
success属性。 stdout和stderr是Buffer实例,而非ReadableStream。- 没有
stdin属性。若需增量写入输入流,请使用Bun.spawn。
Bun.spawn 适合 HTTP 服务器和应用,Bun.spawnSync 更适合构建命令行工具。
性能基准
⚡️
Bun.spawn 和 Bun.spawnSync 使用 posix_spawn(3)。spawnSync 比 Node.js 的 child_process 模块快 60%。
terminal
terminal
参考
以下是 Spawn API 和类型的参考。实际类型包含复杂的泛型,用于根据传递给Bun.spawn 和 Bun.spawnSync 的选项,对 Subprocess 流进行强类型约束。完整详情请参阅 bun.d.ts。
查看可展开的 TypeScript 定义