Skip to main content
Worker API 仍处于实验阶段(尤其是终止 workers 功能)。我们正在积极改进这一点。
借助 Worker,你可以启动一个在独立线程上运行的新 JavaScript 实例,并与其进行通信,同时与主线程共享 I/O 资源。 Bun 实现了 Web Workers API 的一个精简版本,并进行了扩展,使其更适用于服务器端场景。与 Bun 的其他部分一样,Worker 无需额外的构建步骤即可支持 CommonJS、ES 模块、TypeScript、JSX 和 TSX。

创建一个 Worker

与浏览器中一样,Worker 是全局对象。使用它可以创建一个新的工作线程。

在主线程中

index.ts

工作线程

worker.ts
为防止在使用 self 时出现 TypeScript 报错,请在工作线程文件顶部添加以下声明:
你可以在工作线程代码中使用 importexport 语法。与浏览器不同,使用 ES 模块时无需传递 {type: "module"} 如果工作线程的脚本解析失败,Worker 对象会触发一个 "error" 事件。
传递给 Worker 的路径会相对于项目根目录解析(类似于在命令行运行 bun ./path/to/file.js)。

preload - 在 worker 启动前加载模块

将模块说明符数组传递给 preload 选项,以便在工作线程自身的代码运行前加载这些模块,其行为类似于 --preload CLI 参数。可以使用它来加载必须首先加载的代码,例如 OpenTelemetry、Sentry 或 DataDog。
index.ts
你也可以将单个字符串传递给 preload 选项:
index.ts

blob: URL

你也可以将 blob: URL 传递给 Worker,从字符串或其他内存中的源创建工作线程。
与 Bun 的其他部分一样,从 blob: URL 创建的工作线程支持 TypeScript、JSX 和其他文件类型。要告知 Bun 源代码是 TypeScript,请在 Blob 上设置 type,或将 filename 传递给 File 构造函数。

"open" 事件

创建工作线程并准备好接收消息时,会触发 "open" 事件。(浏览器中不存在此事件。)
index.ts
Bun 会将消息排队,直到工作线程准备就绪,因此无需等待 "open" 事件即可发送消息。

使用 postMessage 发送消息

要发送消息,请使用 worker.postMessageself.postMessage。消息使用 HTML 结构化克隆算法 进行序列化。

性能优化

Bun 针对常见数据类型的 postMessage 提供了快速路径: 字符串快速路径 - 发送纯字符串时,Bun 完全绕过结构化克隆算法,因此不会产生序列化开销。 简单对象快速路径 - 对于只包含原始值(字符串、数字、布尔值、null、undefined)的普通对象,Bun 会直接存储属性,而无需进行完整的结构化克隆。 简单对象快速路径适用条件:
  • 是普通对象且没有修改原型链
  • 只包含可枚举、可配置的数据属性
  • 没有索引属性或 getter/setter 方法
  • 所有属性值都是原始类型或字符串
有了这些快速路径,Bun 的 postMessage 性能可提升 2 到 241 倍,消息长度不再显著影响性能。 Bun(含快速路径):
Node.js v24.6.0(对比):
接收消息可使用 worker 或主线程的 message 事件处理器

终止工作线程

Worker 实例会在其事件循环中没有剩余工作时自动终止。在全局对象或任何 MessagePort 上附加 "message" 监听器会使事件循环保持活动状态。要强制终止 Worker,请调用 worker.terminate()
index.ts
调用 worker.terminate() 会使工作线程尽快退出。

process.exit()

工作线程可以调用 process.exit() 自行终止,但这不会终止主进程。与 Node.js 相同,process.on('beforeExit', callback)process.on('exit', callback) 会在工作线程中触发(不会在主线程触发),退出代码会通过 "close" 事件传递。

"close" 事件

当工作线程被标记为已终止时,会触发 "close" 事件;工作线程本身可能需要一些时间才能完全退出。CloseEvent 包含传递给 process.exit() 的退出代码;如果因其他原因关闭,则退出代码为 0。
index.ts
此事件在浏览器中不存在。

生命周期管理

默认情况下,活跃的 Worker 会保持主(创建它的)进程处于运行状态,因此 setTimeout 和 promise 等异步任务会使进程保持运行。附加 message 监听器也会使 Worker 保持运行。

worker.unref()

要阻止正在运行的 worker 使进程保持运行,请调用 worker.unref()。这会将 worker 的生命周期与主进程的生命周期解耦,其行为与 Node.js 的 worker_threads 一致。
index.ts
浏览器不支持 worker.unref()

worker.ref()

要使进程保持运行,直到 Worker 终止,请调用 worker.ref()。默认情况下,Worker 会被引用;被引用的 worker 仍需要其事件循环中存在某些内容(例如 "message" 监听器)才能继续运行。
index.ts
你也可以通过向 Worker 传入 options 对象来设置:
index.ts
浏览器不支持 worker.ref()

使用 smol 模式降低内存使用

Bun 的 Worker 支持 smol 模式,可以降低内存使用,但会牺牲性能。要启用该模式,请在 Worker 构造函数的 options 对象中传入 smol: true
index.ts
设置 smol: true 会将 JSC::HeapSize 设置为 Small,而非默认的 Large

环境数据共享

使用 setEnvironmentData()getEnvironmentData() 在主线程和工作线程间共享数据。
index.ts

Worker 事件

使用 process.on() 监听 worker 创建事件:
index.ts

Bun.isMainThread

检查 Bun.isMainThread 以判断当前是否处于主线程。