> ## Documentation Index
> Fetch the complete documentation index at: https://bun.ll1025.cn/llms.txt
> Use this file to discover all available pages before exploring further.

# Workers

> 使用 Bun 的 Workers API 创建并与运行在单独线程上的新 JavaScript 实例通信，同时与主线程共享 I/O 资源

<Warning>
  `Worker` API 仍处于实验阶段（特别是在终止 worker 方面）。我们正在积极改进。
</Warning>

通过 [`Worker`](https://developer.mozilla.org/zh-CN/docs/Web/API/Worker)，您可以启动并与运行在单独线程上的新 JavaScript 实例通信，同时与主线程共享 I/O 资源。

Bun 实现了 [Web Workers API](https://developer.mozilla.org/zh-CN/docs/Web/API/Web_Workers_API) 的最小版本，并添加了使其更适合服务端使用场景的扩展。与 Bun 的其他部分一样，`Worker` 支持 CommonJS、ES 模块、TypeScript、JSX 和 TSX，无需额外的构建步骤。

## 创建 `Worker`

与浏览器中一样，[`Worker`](https://developer.mozilla.org/zh-CN/docs/Web/API/Worker) 是一个全局对象。使用它来创建一个新的 worker 线程。

### 从主线程

```ts index.ts icon="https://mintcdn.com/span-inc/82N53aP7NFbaCVSl/icons/typescript.svg?fit=max&auto=format&n=82N53aP7NFbaCVSl&q=85&s=787d39d6a7d96d7f9540dc74344eba23" theme={null}
const worker = new Worker("./worker.ts");

worker.postMessage("hello");
worker.onmessage = event => {
  console.log(event.data);
};
```

### Worker 线程

```ts worker.ts icon="file-code" theme={null}
// 防止 TS 错误
declare var self: Worker;

self.onmessage = (event: MessageEvent) => {
  console.log(event.data);
  postMessage("world");
};
```

为防止在使用 `self` 时出现 TypeScript 错误，请在 worker 文件顶部添加此行。

```ts theme={null}
declare var self: Worker;
```

您可以在 worker 代码中使用 `import` 和 `export` 语法。与浏览器不同，您不需要传递 `{type: "module"}` 来使用 ES 模块。

如果 worker 的脚本解析失败，`Worker` 对象上会发出 `"error"` 事件。

```js theme={null}
const worker = new Worker("/not-found.js");
worker.addEventListener("error", event => {
  console.log(event.message);
});
```

传递给 `Worker` 的说明符相对于项目根目录进行解析（类似于在终端中键入 `bun ./path/to/file.js`）。

### `preload` - 在 worker 启动前加载模块

将模块说明符数组传递给 `preload` 选项，可在 worker 自身代码运行之前加载它们，类似于 `--preload` CLI 参数。用于必须优先加载的代码，例如 OpenTelemetry、Sentry 或 DataDog。

```ts index.ts icon="https://mintcdn.com/span-inc/82N53aP7NFbaCVSl/icons/typescript.svg?fit=max&auto=format&n=82N53aP7NFbaCVSl&q=85&s=787d39d6a7d96d7f9540dc74344eba23" theme={null}
const worker = new Worker("./worker.ts", {
  preload: ["./load-sentry.js"],
});
```

您也可以将单个字符串传递给 `preload` 选项：

```ts index.ts icon="https://mintcdn.com/span-inc/82N53aP7NFbaCVSl/icons/typescript.svg?fit=max&auto=format&n=82N53aP7NFbaCVSl&q=85&s=787d39d6a7d96d7f9540dc74344eba23" theme={null}
const worker = new Worker("./worker.ts", {
  preload: "./load-sentry.js",
});
```

### `blob:` URL

您也可以将 `blob:` URL 传递给 `Worker`，以从字符串或其他内存源码创建 worker。

```js theme={null}
const blob = new Blob([`self.onmessage = (event: MessageEvent) => postMessage(event.data)`], {
  type: "application/typescript",
});
const url = URL.createObjectURL(blob);
const worker = new Worker(url);
```

与 Bun 的其他部分一样，从 `blob:` URL 创建的 worker 支持 TypeScript、JSX 和其他文件类型。要告诉 Bun 源码是 TypeScript，请在 `Blob` 上设置 `type`，或在 `File` 构造函数中传递 `filename`。

```ts theme={null}
const file = new File([`self.onmessage = (event: MessageEvent) => postMessage(event.data)`], "worker.ts");
const url = URL.createObjectURL(file);
const worker = new Worker(url);
```

### `"open"`

当 worker 创建完成并准备好接收消息时，会发出 `"open"` 事件。（此事件在浏览器中不存在。）

```ts index.ts icon="https://mintcdn.com/span-inc/82N53aP7NFbaCVSl/icons/typescript.svg?fit=max&auto=format&n=82N53aP7NFbaCVSl&q=85&s=787d39d6a7d96d7f9540dc74344eba23" theme={null}
const worker = new Worker(new URL("worker.ts", import.meta.url).href);

worker.addEventListener("open", () => {
  console.log("worker is ready");
});
```

Bun 会在 worker 准备好之前将消息排队，因此您无需在发送消息前等待 `"open"` 事件。

## 使用 `postMessage` 发送消息

要发送消息，请使用 [`worker.postMessage`](https://developer.mozilla.org/zh-CN/docs/Web/API/Worker/postMessage) 和 [`self.postMessage`](https://developer.mozilla.org/zh-CN/docs/Web/API/Window/postMessage)。消息使用 [HTML 结构化克隆算法](https://developer.mozilla.org/zh-CN/docs/Web/API/Web_Workers_API/Structured_clone_algorithm) 进行序列化。

### 性能优化

Bun 对常见数据类型的 `postMessage` 有快速路径：

**字符串快速路径** - 当发送纯字符串时，Bun 完全绕过结构化克隆算法，因此没有序列化开销。

**简单对象快速路径** - 对于仅包含原始值（字符串、数字、布尔值、null、undefined）的纯对象，Bun 直接存储属性，无需完整结构化克隆。

满足以下条件的对象会触发简单对象快速路径：

* 是没有原型链修改的纯对象
* 仅包含可枚举、可配置的数据属性
* 没有索引属性或 getter/setter 方法
* 所有属性值都是原始值或字符串

通过这些快速路径，Bun 的 `postMessage` 性能提升 **2-241 倍**，因为消息长度不再对性能产生显著影响。

**Bun（带快速路径）：**

```ts theme={null}
postMessage({ prop: 11 chars string, ...9 more props }) - 648ns
postMessage({ prop: 14 KB string, ...9 more props })    - 719ns
postMessage({ prop: 3 MB string, ...9 more props })     - 1.26µs
```

**Node.js v24.6.0（供对比）：**

```js theme={null}
postMessage({ prop: 11 chars string, ...9 more props }) - 1.19µs
postMessage({ prop: 14 KB string, ...9 more props })    - 2.69µs
postMessage({ prop: 3 MB string, ...9 more props })     - 304µs
```

```js theme={null}
// 字符串快速路径 - 已优化
postMessage("Hello, worker!");

// 简单对象快速路径 - 已优化
postMessage({
  message: "Hello",
  count: 42,
  enabled: true,
  data: null,
});

// 复杂对象仍然工作，但使用标准结构化克隆
postMessage({
  nested: { deep: { object: true } },
  date: new Date(),
  buffer: new ArrayBuffer(8),
});
```

```js theme={null}
// 在 worker 线程中，`postMessage` 自动"路由"到父线程。
postMessage({ hello: "world" });

// 在主线程中
worker.postMessage({ hello: "world" });
```

要接收消息，请在 worker 和主线程上使用 [`message` 事件处理器](https://developer.mozilla.org/zh-CN/docs/Web/API/Worker/message_event)。

```js theme={null}
// Worker 线程：
self.addEventListener("message", event => {
  console.log(event.data);
});
// 或使用 setter：
// self.onmessage = fn

// 如果在主线程
worker.addEventListener("message", event => {
  console.log(event.data);
});
// 或使用 setter：
// worker.onmessage = fn
```

## 终止 worker

`Worker` 实例在其事件循环没有剩余任务可执行时会自动终止。在全局对象或任何 `MessagePort` 上附加 `"message"` 监听器会保持事件循环运行。要强制终止 `Worker`，请调用 `worker.terminate()`。

```ts index.ts icon="https://mintcdn.com/span-inc/82N53aP7NFbaCVSl/icons/typescript.svg?fit=max&auto=format&n=82N53aP7NFbaCVSl&q=85&s=787d39d6a7d96d7f9540dc74344eba23" theme={null}
const worker = new Worker(new URL("worker.ts", import.meta.url).href);

// ...一段时间后
worker.terminate();
```

调用 `worker.terminate()` 会使 worker 尽快退出。

### `process.exit()`

worker 可以使用 `process.exit()` 自行终止。这不会终止主进程。与 Node.js 一样，`process.on('beforeExit', callback)` 和 `process.on('exit', callback)` 会在 worker 线程上触发（而不是在主线程上），并且退出代码会传递给 `"close"` 事件。

### `"close"`

当 worker 被标记为已终止时，会发出 `"close"` 事件；worker 本身可能需要一些时间才能完全退出。`CloseEvent` 包含传递给 `process.exit()` 的退出代码，如果因其他原因关闭则为 0。

```ts index.ts icon="https://mintcdn.com/span-inc/82N53aP7NFbaCVSl/icons/typescript.svg?fit=max&auto=format&n=82N53aP7NFbaCVSl&q=85&s=787d39d6a7d96d7f9540dc74344eba23" theme={null}
const worker = new Worker(new URL("worker.ts", import.meta.url).href);

worker.addEventListener("close", event => {
  console.log("worker is being closed");
});
```

此事件在浏览器中不存在。

## 管理生命周期

默认情况下，活跃的 `Worker` 会保持主（启动）进程存活，因此像 `setTimeout` 和 promise 这样的异步任务会保持进程运行。附加 `message` 监听器也会保持 `Worker` 存活。

### `worker.unref()`

要阻止正在运行的 worker 保持进程存活，请调用 `worker.unref()`。这会将 worker 的生命周期与主进程解耦，与 Node.js 的 `worker_threads` 行为一致。

```ts index.ts icon="https://mintcdn.com/span-inc/82N53aP7NFbaCVSl/icons/typescript.svg?fit=max&auto=format&n=82N53aP7NFbaCVSl&q=85&s=787d39d6a7d96d7f9540dc74344eba23" theme={null}
const worker = new Worker(new URL("worker.ts", import.meta.url).href);
worker.unref();
```

`worker.unref()` 在浏览器中不可用。

### `worker.ref()`

要保持进程存活直到 `Worker` 终止，请调用 `worker.ref()`。Worker 默认是 ref 状态；ref 状态的 worker 仍然需要其事件循环上有任务（例如 `"message"` 监听器）才能继续运行。

```ts index.ts icon="https://mintcdn.com/span-inc/82N53aP7NFbaCVSl/icons/typescript.svg?fit=max&auto=format&n=82N53aP7NFbaCVSl&q=85&s=787d39d6a7d96d7f9540dc74344eba23" theme={null}
const worker = new Worker(new URL("worker.ts", import.meta.url).href);
worker.unref();
// 稍后...
worker.ref();
```

或者，您也可以向 `Worker` 传递一个 `options` 对象：

```ts index.ts icon="https://mintcdn.com/span-inc/82N53aP7NFbaCVSl/icons/typescript.svg?fit=max&auto=format&n=82N53aP7NFbaCVSl&q=85&s=787d39d6a7d96d7f9540dc74344eba23" theme={null}
const worker = new Worker(new URL("worker.ts", import.meta.url).href, {
  ref: false,
});
```

`worker.ref()` 在浏览器中不可用。

## 使用 `smol` 节约内存

Bun 的 `Worker` 支持 `smol` 模式，可以在牺牲性能的情况下减少内存使用。要启用它，请在 `Worker` 构造函数的 `options` 对象中传递 `smol: true`。

```ts index.ts icon="https://mintcdn.com/span-inc/82N53aP7NFbaCVSl/icons/typescript.svg?fit=max&auto=format&n=82N53aP7NFbaCVSl&q=85&s=787d39d6a7d96d7f9540dc74344eba23" theme={null}
const worker = new Worker("./i-am-smol.ts", {
  smol: true,
});
```

<Accordion title="`smol` 模式实际上做了什么？">
  设置 `smol: true` 会将 `JSC::HeapSize` 设置为 `Small` 而不是默认的 `Large`。
</Accordion>

## 环境数据

使用 `setEnvironmentData()` 和 `getEnvironmentData()` 在主线程和 worker 之间共享数据。

```ts title="index.ts" icon="https://mintcdn.com/span-inc/82N53aP7NFbaCVSl/icons/typescript.svg?fit=max&auto=format&n=82N53aP7NFbaCVSl&q=85&s=787d39d6a7d96d7f9540dc74344eba23" theme={null}
import { setEnvironmentData, getEnvironmentData } from "worker_threads";

// 在主线程中
setEnvironmentData("config", { apiUrl: "https://api.example.com" });

// 在 worker 中
const config = getEnvironmentData("config");
console.log(config); // => { apiUrl: "https://api.example.com" }
```

## Worker 事件

使用 `process.on()` 监听 worker 创建事件：

```ts title="index.ts" icon="https://mintcdn.com/span-inc/82N53aP7NFbaCVSl/icons/typescript.svg?fit=max&auto=format&n=82N53aP7NFbaCVSl&q=85&s=787d39d6a7d96d7f9540dc74344eba23" theme={null}
process.on("worker", worker => {
  console.log("New worker created:", worker.threadId);
});
```

## `Bun.isMainThread`

检查 `Bun.isMainThread` 来判断您是否在主线程上。

```ts theme={null}
if (Bun.isMainThread) {
  console.log("I'm the main thread");
} else {
  console.log("I'm in a worker");
}
```
