Worker,你可以启动一个在独立线程上运行的新 JavaScript 实例,并与其进行通信,同时与主线程共享 I/O 资源。
Bun 实现了 Web Workers API 的一个精简版本,并进行了扩展,使其更适用于服务器端场景。与 Bun 的其他部分一样,Worker 无需额外的构建步骤即可支持 CommonJS、ES 模块、TypeScript、JSX 和 TSX。
创建一个 Worker
与浏览器中一样,Worker 是全局对象。使用它可以创建一个新的工作线程。
在主线程中
index.ts
工作线程
worker.ts
self 时出现 TypeScript 报错,请在工作线程文件顶部添加以下声明:
import 和 export 语法。与浏览器不同,使用 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,从字符串或其他内存中的源创建工作线程。
blob: URL 创建的工作线程支持 TypeScript、JSX 和其他文件类型。要告知 Bun 源代码是 TypeScript,请在 Blob 上设置 type,或将 filename 传递给 File 构造函数。
"open" 事件
创建工作线程并准备好接收消息时,会触发 "open" 事件。(浏览器中不存在此事件。)
index.ts
"open" 事件即可发送消息。
使用 postMessage 发送消息
要发送消息,请使用 worker.postMessage 和 self.postMessage。消息使用 HTML 结构化克隆算法 进行序列化。
性能优化
Bun 针对常见数据类型的postMessage 提供了快速路径:
字符串快速路径 - 发送纯字符串时,Bun 完全绕过结构化克隆算法,因此不会产生序列化开销。
简单对象快速路径 - 对于只包含原始值(字符串、数字、布尔值、null、undefined)的普通对象,Bun 会直接存储属性,而无需进行完整的结构化克隆。
简单对象快速路径适用条件:
- 是普通对象且没有修改原型链
- 只包含可枚举、可配置的数据属性
- 没有索引属性或 getter/setter 方法
- 所有属性值都是原始类型或字符串
postMessage 性能可提升 2 到 241 倍,消息长度不再显著影响性能。
Bun(含快速路径):
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` 模式究竟做了什么?
`smol` 模式究竟做了什么?
设置
smol: true 会将 JSC::HeapSize 设置为 Small,而非默认的 Large。环境数据共享
使用setEnvironmentData() 和 getEnvironmentData() 在主线程和工作线程间共享数据。
index.ts
Worker 事件
使用process.on() 监听 worker 创建事件:
index.ts
Bun.isMainThread
检查 Bun.isMainThread 以判断当前是否处于主线程。