创建一个进程 (Bun.spawn())
提供一个字符串数组作为命令。Bun.spawn() 返回一个 Bun.Subprocess 对象。
Bun.spawn 的第二个参数是一个参数对象,用来配置子进程。
输入流
默认情况下,子进程的输入流是undefined;可以通过 stdin 参数进行配置。
| 值 | 描述 |
|---|---|
null | 默认。 不向子进程提供输入 |
"pipe" | 返回一个 FileSink 用于快速增量写入 |
"inherit" | 继承父进程的 stdin |
Bun.file() | 从指定文件读取 |
TypedArray | DataView | 使用二进制缓冲区作为输入 |
Response | 使用响应体 body 作为输入 |
Request | 使用请求体 body 作为输入 |
ReadableStream | 使用可读流作为输入 |
Blob | 使用 Blob 作为输入 |
number | 从给定文件描述符的文件读取 |
"pipe" 选项允许从父进程向子进程的输入流进行增量写入。
ReadableStream 传给 stdin,可以让你直接从 JavaScript 的 ReadableStream 向子进程输入流传输数据:
输出流
你可以通过stdout 和 stderr 属性读取子进程的输出。默认情况下它们是 ReadableStream 的实例。
stdout/stderr 传入以下值之一来配置输出流:
| 值 | 描述 |
|---|---|
"pipe" | stdout 的默认值。 将输出导入返回的 Subprocess 对象的 ReadableStream |
"inherit" | stderr 的默认值。 继承自父进程 |
"ignore" | 丢弃输出 |
Bun.file() | 写入指定文件 |
number | 写入指定文件描述符的文件 |
退出处理
使用onExit 回调监听进程退出或被杀死。
exited 属性是一个在进程退出时解析的 Promise。
bun 在所有子进程退出前不会终止。使用 proc.unref() 可以将子进程与父进程分离。
资源使用
进程退出后,你可以获取该进程的资源使用信息:使用 AbortSignal
你可以使用AbortSignal 中止子进程:
使用 timeout 和 killSignal
你可以为子进程设置超时时间,超时后自动终止进程:SIGTERM 信号被杀死。你可以通过 killSignal 选项指定不同信号:
killSignal 选项也控制在 AbortSignal 触发时发送的信号。
使用 maxBuffer
对于 spawnSync,你可以限制输出的最大字节数,超过则杀死进程:进程间通信 (IPC)
Bun 支持在两个bun 进程间建立直接的进程间通信通道。要从被创建的 Bun 子进程接收消息,请指定 ipc 处理器。
Subprocess 对象上的 .send() 方法向子进程发送消息。子进程在 ipc 处理器第二个参数中获得发送者引用。
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访问终端
终端选项
| 选项 | 描述 | 默认值 |
|---|---|---|
cols | 列数 | 80 |
rows | 行数 | 24 |
name | PTY 配置的终端类型(通过 env 选项单独设置 TERM 环境变量) | "xterm-256color" |
data | 接收数据时回调 (terminal, data) => void | — |
exit | PTY 流关闭时回调(EOF 或错误)。exitCode 是 PTY 生命周期状态(0为EOF,1为错误),而非子进程退出码。使用 proc.exited 监听进程退出。 | — |
drain | 可写流准备好接收更多数据时回调 (terminal) => void | — |
终端方法
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。 - 子进程中的
process.on('SIGWINCH')在 ConPTY 下不会触发,除非子进程以原始模式读取 stdin。process.stdout.columns/rows会在resize()后更新。这是一个 libuv 限制,影响所有基于 libuv 的子进程(包括 Node.js)。 - 在 Windows 11 24H2(build 26100)之前,
terminal.close()可能不会立即终止仍在运行的子进程,因为在这些版本上ClosePseudoConsole会阻塞,直到 conhost 将其输出通过管道刷新完毕。如果你需要在子进程运行时拆除环境,请先杀死附加的进程。
阻塞式 API (Bun.spawnSync())
Bun 提供了 Bun.spawn 的同步版本 Bun.spawnSync。这是一个阻塞 API,支持与 Bun.spawn 相同的输入和参数。它返回一个 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 中的定义。
See Typescript Definitions