稳定性:2 - 稳定
node:worker_threads 模块允许使用并行执行 JavaScript 的线程。要访问它:
import worker_threads from 'node:worker_threads';工作器(线程)适用于执行 CPU 密集型的 JavaScript 操作。它们对 I/O 密集型工作帮助不大。Node.js 内置的异步 I/O 操作比工作器更高效。
与 child_process 或 cluster 不同,worker_threads 可以共享内存。它们通过传输 ArrayBuffer 实例或共享 SharedArrayBuffer 实例来实现这一点。
import {
Worker,
isMainThread,
parentPort,
workerData,
} from 'node:worker_threads';
if (!isMainThread) {
const { parse } = await import('some-js-parsing-library');
const script = workerData;
parentPort.postMessage(parse(script));
}
export default function parseJSAsync(script) {
return new Promise((resolve, reject) => {
const worker = new Worker(new URL(import.meta.url), {
workerData: script,
});
worker.on('message', resolve);
worker.once('error', reject);
worker.once('exit', (code) => {
if (code !== 0)
reject(new Error(`Worker 已停止,退出代码为 ${code}`));
});
});
};上述示例为每个 parseJSAsync() 调用生成一个 Worker 线程。实际上,对于此类任务应使用 Worker 池。否则,创建 Worker 的开销可能会超过其收益。
实现 Worker 池时,使用 AsyncResource API 通知诊断工具(例如提供异步堆栈跟踪)关于任务与其结果之间的关联。有关示例实现,请参阅 async_hooks 文档中的 "使用 AsyncResource 用于 Worker 线程池"。
Worker 线程默认继承非进程特定的选项。参阅 Worker 构造函数选项 了解如何自定义工作线程选项,特别是 argv 和 execArgv 选项。
在工作线程内,worker.getEnvironmentData() 返回传递给生成线程的 worker.setEnvironmentData() 的数据克隆。每个新 Worker 都会自动接收环境数据的自己的副本。
import {
Worker,
isMainThread,
setEnvironmentData,
getEnvironmentData,
} from 'node:worker_threads';
if (isMainThread) {
setEnvironmentData('Hello', 'World!');
const worker = new Worker(new URL(import.meta.url));
} else {
console.log(getEnvironmentData('Hello')); // 打印 'World!'。
}- 类型:
<boolean>
如果此代码在内部 Worker 线程(例如加载器线程)内运行,则为 true。
node --experimental-loader ./loader.js main.js- 类型:
<boolean>
如果此代码不在 Worker 线程内运行,则为 true。
import { Worker, isMainThread } from 'node:worker_threads';
if (isMainThread) {
// 这会在 Worker 实例中重新加载当前文件。
new Worker(new URL(import.meta.url));
} else {
console.log('在 Worker 内部!');
console.log(isMainThread); // 打印 'false'.
}<any>将对象标记为不可传输。如果 object 出现在 port.postMessage() 调用的传输列表中,则会抛出错误。如果 object 是原始值,则此操作无效。
特别是,这对于可以被克隆而不是传输,并且被发送方其他对象使用的对象是有意义的。例如,Node.js 用它来标记用于 Buffer 池 的 ArrayBuffer。在此类数组缓冲区实例上禁止使用 ArrayBuffer.prototype.transfer()。
此操作无法撤销。
import { MessageChannel, markAsUntransferable } from 'node:worker_threads';
const pooledBuffer = new ArrayBuffer(8);
const typedArray1 = new Uint8Array(pooledBuffer);
const typedArray2 = new Float64Array(pooledBuffer);
markAsUntransferable(pooledBuffer);
const { port1 } = new MessageChannel();
try {
// 这将抛出一个错误,因为 pooledBuffer 不可传输。
port1.postMessage(typedArray1, [ typedArray1.buffer ]);
} catch (error) {
// error.name === 'DataCloneError'
}
// 以下行打印 typedArray1 的内容 -- 它仍然拥有
// 其内存且未被传输。如果没有
// `markAsUntransferable()`,这将打印一个空的 Uint8Array 并且
// postMessage 调用会成功。
// typedArray2 也完好无损。
console.log(typedArray1);
console.log(typedArray2);浏览器中没有与此 API 等效的功能。<any>
检查对象是否被 markAsUntransferable() 标记为不可传输。
import { markAsUntransferable, isMarkedAsUntransferable } from 'node:worker_threads';
const pooledBuffer = new ArrayBuffer(8);
markAsUntransferable(pooledBuffer);
isMarkedAsUntransferable(pooledBuffer); // 返回 true。浏览器中没有与此 API 等效的功能。<any>
将对象标记为不可克隆。如果 object 在 port.postMessage() 调用中用作 message,则会抛出错误。如果 object 是原始值,则此操作无效。
这对 ArrayBuffer 或任何 Buffer 类对象没有影响。
此操作无法撤销。
import { markAsUncloneable } from 'node:worker_threads';
const anyObject = { foo: 'bar' };
markAsUncloneable(anyObject);
const { port1 } = new MessageChannel();
try {
// 这将抛出一个错误,因为 anyObject 不可克隆。
port1.postMessage(anyObject);
} catch (error) {
// error.name === 'DataCloneError'
}浏览器中没有与此 API 等效的功能。<MessagePort><Object>vm.createContext()
方法返回。
将 MessagePort 传输到不同的 vm 上下文。原始 port 对象变为不可用,返回的 MessagePort 实例取代其位置。
返回的 MessagePort 是目标上下文中的对象,并继承自其全局 Object 类。传递给 port.onmessage() 监听器的对象也在目标上下文中创建,并继承自其全局 Object 类。
但是,创建的 MessagePort 不再继承自 <EventTarget>,只能使用 port.onmessage() 来接收事件。
- 类型:
<null>|<MessagePort>
如果此线程是一个 Worker,则这是一个 MessagePort,
允许与主线程通信。使用 parentPort.postMessage() 发送的消息在主线程中
通过 worker.on('message') 可用,而使用 worker.postMessage() 从主线程
发送的消息在此线程中通过 parentPort.on('message') 可用。
import { Worker, isMainThread, parentPort } from 'node:worker_threads';
if (isMainThread) {
const worker = new Worker(new URL(import.meta.url));
worker.once('message', (message) => {
console.log(message); // 打印 'Hello, world!'。
});
worker.postMessage('Hello, world!');
} else {
// 当收到来自主线程的消息时,将其发回:
parentPort.once('message', (message) => {
parentPort.postMessage(message);
});
}稳定性:1.1 - 积极开发中
<number>ERR_WORKER_MESSAGING_FAILED
错误。如果目标线程 ID 是当前线程 ID,
将抛出
ERR_WORKER_MESSAGING_SAME_THREAD
错误。<any><Object>value
中传递了一个或多个
MessagePort
类似对象,
则这些项需要
transferList
,否则将抛出
ERR_MISSING_MESSAGE_PORT_IN_TRANSFER_LIST
。
参见
port.postMessage()
获取更多信息。<number>undefined
,表示永远等待。如果操作超时,
将抛出
ERR_WORKER_MESSAGING_TIMEOUT
错误。向另一个 worker 发送一个值,由其线程 ID 标识。
如果目标线程没有 workerMessage 事件的监听器,则操作将抛出
ERR_WORKER_MESSAGING_FAILED 错误。
如果目标线程在处理 workerMessage 事件时抛出错误,则操作将抛出
ERR_WORKER_MESSAGING_ERRORED 错误。
当目标线程不是当前线程的直接父线程或子线程时,应使用此方法。
如果两个线程是父子关系,请使用 require('node:worker_threads').parentPort.postMessage()
和 worker.postMessage() 让线程通信。
下面的示例展示了 postMessageToThread 的用法:它创建了 10 个嵌套线程,
最后一个线程会尝试与主线程通信。
import process from 'node:process';
import {
postMessageToThread,
threadId,
workerData,
Worker,
} from 'node:worker_threads';
const channel = new BroadcastChannel('sync');
const level = workerData?.level ?? 0;
if (level < 10) {
const worker = new Worker(new URL(import.meta.url), {
workerData: { level: level + 1 },
});
}
if (level === 0) {
process.on('workerMessage', (value, source) => {
console.log(`${source} -> ${threadId}:`, value);
postMessageToThread(source, { message: 'pong' });
});
} else if (level === 10) {
process.on('workerMessage', (value, source) => {
console.log(`${source} -> ${threadId}:`, value);
channel.postMessage('done');
channel.close();
});
await postMessageToThread(0, { message: 'ping' });
}
channel.onmessage = channel.close;<MessagePort>
|
<BroadcastChannel>从给定的 MessagePort 接收单条消息。如果没有可用消息,
则返回 undefined,否则返回一个包含单个 message 属性的对象,
该属性包含消息负载,对应于 MessagePort 队列中最旧的消息。
import { MessageChannel, receiveMessageOnPort } from 'node:worker_threads';
const { port1, port2 } = new MessageChannel();
port1.postMessage({ hello: 'world' });
console.log(receiveMessageOnPort(port2));
// 打印:{ message: { hello: 'world' } }
console.log(receiveMessageOnPort(port2));
// 打印:undefined使用此函数时,不会发出 'message' 事件,也不会调用
onmessage 监听器。
- 类型:
<Object>Attributes
提供此 Worker 线程内 JS 引擎资源约束的集合。
如果将 resourceLimits 选项传递给 Worker 构造函数,
则与此值匹配。
如果在主线程中使用此选项,其值为一个空对象。
- 类型:
<symbol>
一个特殊值,可作为 Worker 构造函数的 env 选项传递,
以指示当前线程和 Worker 线程应共享对同一组环境变量的读写访问权限。
import process from 'node:process';
import { Worker, SHARE_ENV } from 'node:worker_threads';
new Worker('process.env.SET_IN_WORKER = "foo"', { eval: true, env: SHARE_ENV })
.once('exit', () => {
console.log(process.env.SET_IN_WORKER); // 打印 'foo'。
});worker.setEnvironmentData() API 设置当前线程和从当前上下文
生成的所有新 Worker 实例中 worker.getEnvironmentData() 的内容。
- 类型:
<integer>
当前线程的整数标识符。在相应的 worker 对象上
(如果有的话),它可作为 worker.threadId 使用。
此值在单个进程内的每个 Worker 实例中都是唯一的。
当前线程的字符串标识符,如果线程未运行则为 null。
在相应的 worker 对象上(如果有的话),它可作为 worker.threadName 使用。
任意 JavaScript 值,包含传递给此线程的 Worker 构造函数的数据的克隆。
数据的克隆方式如同使用 postMessage(),
根据 HTML 结构化克隆算法。
import { Worker, isMainThread, workerData } from 'node:worker_threads';
if (isMainThread) {
const worker = new Worker(new URL(import.meta.url), { workerData: 'Hello, world!' });
} else {
console.log(workerData); // 打印 'Hello, world!'。
}稳定性:1 - 实验性
一个 LockManager 实例,可用于协调同一进程内多个线程之间可能共享的资源访问。该 API 镜像了
[浏览器 LockManager][] 的语义。
锁的名称。
锁的模式。shared 或 exclusive。
import { locks } from 'node:worker_threads';此实现与 [浏览器 LockManager][] API 匹配。<string><Object><string>'exclusive'
或
'shared'
。
默认值:
'exclusive'
。<boolean>true
,则仅当锁未被持有时才授予请求。如果无法授予,
callback
将
使用
null
调用,而不是
Lock
实例。
默认值:
false
。<boolean>true
,则释放任何具有相同名称的现有锁,并立即授予请求,抢占任何排队的
请求。
默认值:
false
。<AbortSignal><Function>ifAvailable
为
true
且锁不可用,则立即使用
null
调用)。当函数返回时,锁会自动释放,或者——如果函数返回
一个 promise——当该 promise 解决时。
import { locks } from 'node:worker_threads';
await locks.request('my_resource', async (lock) => {
// 锁已获取。
});
// 锁在此处已释放。- 返回:
<Promise>
解析为一个 LockManagerSnapshot,描述当前进程当前持有和待处理的锁。
import { locks } from 'node:worker_threads';
const snapshot = await locks.query();
for (const lock of snapshot.held) {
console.log(`held lock: name ${lock.name}, mode ${lock.mode}`);
}
for (const pending of snapshot.pending) {
console.log(`pending lock: name ${pending.name}, mode ${pending.mode}`);
}BroadcastChannel 的实例允许与所有绑定到相同通道名称的其他 BroadcastChannel 实例进行异步一对多通信。
import {
isMainThread,
BroadcastChannel,
Worker,
} from 'node:worker_threads';
const bc = new BroadcastChannel('hello');
if (isMainThread) {
let c = 0;
bc.onmessage = (event) => {
console.log(event.data);
if (++c === 10) bc.close();
};
for (let n = 0; n < 10; n++)
new Worker(new URL(import.meta.url));
} else {
bc.postMessage('hello from every worker');
bc.close();
}worker.MessageChannel 类的实例表示一个异步双向通信通道。
MessageChannel 没有自己的方法。new MessageChannel() 生成一个带有 port1 和 port2 属性的对象,这些属性引用链接的 MessagePort 实例。
import { MessageChannel } from 'node:worker_threads';
const { port1, port2 } = new MessageChannel();
port1.on('message', (message) => console.log('received', message));
port2.postMessage({ foo: 'bar' });
// 打印:received { foo: 'bar' } 来自 `port1.on('message')` 监听器- 继承自:
<EventTarget>
worker.MessagePort 类的实例表示异步双向通信通道的一端。它可用于在不同的 Worker 之间传输结构化数据、内存区域和其他 MessagePort。
此实现与 [浏览器 MessagePort][] 匹配。
import { MessageChannel } from 'node:worker_threads';
const { port1, port2 } = new MessageChannel();
// 打印:
// foobar
// 关闭!
port2.on('message', (message) => console.log(message));
port2.once('close', () => console.log('关闭!'));
port1.postMessage('foobar');
port1.close();对于任何传入的消息,都会发出 'message' 事件,包含 port.postMessage() 的克隆输入。
此事件的监听器接收传递给 postMessage() 的 value 参数的克隆,没有进一步的参数。
当反序列化消息失败时,会发出 'messageerror' 事件。
目前,当在接收端实例化发布的 JS 对象发生错误时,会发出此事件。这种情况很少见,但可能会发生,例如,当在 vm.Context 中接收到某些 Node.js API 对象时(目前在该上下文中 Node.js API 不可用)。
['close' 事件][] 会在属于该通道的两个 MessagePort` 实例上发出。
将 JavaScript 值发送到此通道的接收端。
value 以与 HTML 结构化克隆算法 兼容的方式进行传输。
特别是,与 JSON 的显著区别是:
value可能包含循环引用。value可能包含内置 JS 类型的实例,例如RegExp、BigInt、Map、Set等。value可能包含类型化数组,既可以使用ArrayBuffer,也可以使用SharedArrayBuffer。value可能包含WebAssembly.Module实例。value不能包含原生(C++ 支持的)对象,以下对象除外:Attributess(仅 TCP,且在transferList中列出时),s(仅 TCP,且在transferList中列出时),
import { MessageChannel } from 'node:worker_threads';
const { port1, port2 } = new MessageChannel();
port1.on('message', (message) => console.log(message));
const circularData = {};
circularData.foo = circularData;
// 打印:{ foo: [Circular] }
port2.postMessage(circularData);transferList 可能是 <ArrayBuffer>、MessagePort、FileHandle、<net.Server> 和 <net.Socket> 对象的列表。
传输后,它们在通道发送端将不再可用(即使它们不包含在 value 中也是如此)。
传输 <net.Server> 会将其监听套接字——以及接受队列中的任何待处理连接——移动到接收线程的事件循环中。
传输 <net.Socket> 会移动单个连接;该套接字必须是新近接受或创建的、尚未开始读取且没有缓冲数据的 TCP 连接,否则 postMessage() 会抛出
ERR_WORKER_HANDLE_NOT_TRANSFERABLE。这使得可以在一个线程上接受连接,并将它们分发到一个 worker 线程池中。
仅支持 TCP 句柄,并且仅在类 Unix 平台上支持;在 Windows 上,postMessage() 会抛出 ERR_WORKER_HANDLE_TRANSFER_UNSUPPORTED。
如果 value 包含 <SharedArrayBuffer> 实例,则它们可从任一线程访问。它们不能列在 transferList 中。
value 可能仍然包含不在 transferList 中的 ArrayBuffer 实例;在这种情况下,底层内存会被复制而不是移动。
import { MessageChannel } from 'node:worker_threads';
const { port1, port2 } = new MessageChannel();
port1.on('message', (message) => console.log(message));
const uint8Array = new Uint8Array([ 1, 2, 3, 4 ]);
// 这会发布 `uint8Array` 的副本:
port2.postMessage(uint8Array);
// 这不会复制数据,但会使 `uint8Array` 不可用:
port2.postMessage(uint8Array, [ uint8Array.buffer ]);
// `sharedUint8Array` 的内存可从原始副本和 `.on('message')` 接收的副本中访问:
const sharedUint8Array = new Uint8Array(new SharedArrayBuffer(4));
port2.postMessage(sharedUint8Array);
// 这将新创建的消息端口传输给接收者。
// 例如,这可用于在作为同一父线程子线程的多个 `Worker` 线程之间创建通信通道。
const otherChannel = new MessageChannel();
port2.postMessage({ port: otherChannel.port1 }, [ otherChannel.port1 ]);消息对象会立即被克隆,并且可以在发布后修改而不会产生副作用。
有关此 API 背后的序列化和反序列化机制的更多信息,请参阅 node:v8 模块的序列化 API。
所有 <TypedArray> | <Buffer> 实例都是底层 <ArrayBuffer> 的视图。也就是说,实际上是 ArrayBuffer 存储原始数据,而 TypedArray 和 Buffer 对象提供了一种查看和操作数据的方式。为同一个 ArrayBuffer 实例创建多个视图是可能且常见的。在使用传输列表传输 ArrayBuffer 时必须非常小心,因为这样做会导致共享该 ArrayBuffer 的所有 TypedArray 和 Buffer 实例变得不可用。
const ab = new ArrayBuffer(10);
const u1 = new Uint8Array(ab);
const u2 = new Uint16Array(ab);
console.log(u2.length); // 打印 5
port.postMessage(u1, [u1.buffer]);
console.log(u2.length); // 打印 0具体对于 Buffer 实例,底层的 ArrayBuffer 是可以传输还是克隆完全取决于实例是如何创建的,这通常无法可靠地确定。
可以使用 markAsUntransferable() 标记 ArrayBuffer,以指示它应该始终被克隆而从不被传输。
根据 Buffer 实例的创建方式,它可能拥有也可能不拥有其底层的 ArrayBuffer。除非已知 Buffer 实例拥有 ArrayBuffer,否则不得传输 ArrayBuffer。特别是,对于从内部 Buffer 池创建的 Buffer(例如使用 Buffer.from() 或 Buffer.allocUnsafe()),无法传输它们,它们总是被克隆,这会发送整个 Buffer 池的副本。这种行为可能会带来意外的高内存使用和可能的安全隐患。
有关 Buffer 池化的更多详细信息,请参阅 Buffer.allocUnsafe()。
使用 Buffer.alloc() 或 Buffer.allocUnsafeSlow() 创建的 Buffer 实例的 ArrayBuffer 始终可以传输,但这样做会使这些 ArrayBuffer 的所有其他现有视图不可用。
因为对象克隆使用 HTML 结构化克隆算法,所以不可枚举的属性、属性访问器和对象原型不会被保留。特别是,<Buffer> 对象在接收端将被读取为普通的 <Uint8Array>,JavaScript 类的实例将被克隆为普通的 JavaScript 对象。
const b = Symbol('b');
class Foo {
#a = 1;
constructor() {
this[b] = 2;
this.c = 3;
}
get d() { return this.#a + 3; }
}
const { port1, port2 } = new MessageChannel();
port1.onmessage = ({ data }) => console.log(data);
port2.postMessage(new Foo());
// 打印:{ c: 3 }一些内置对象根本无法克隆。例如,发送一个
URL 对象会抛出 DataCloneError:
const { port1, port2 } = new MessageChannel();
port2.postMessage(new URL('https://example.org'));
// 抛出 DataCloneError:无法克隆不受支持类型的对象。如果为 true,MessagePort 对象将保持 Node.js 事件循环活动。
如果使用 .on('message') 附加或移除监听器,端口会根据是否存在事件监听器自动 ref() 和 unref()。
此方法存在是为了与 Web MessagePort API 保持一致。在 Node.js 中,它仅用于在没有事件监听器时忽略消息。Node.js 在处理 .onmessage 方面也有所不同。设置它会自动调用 .start(),但取消设置它会让消息排队,直到设置新的处理程序或端口被丢弃。
如果使用 .on('message') 附加或移除监听器,端口会根据是否存在事件监听器自动 ref() 和 unref()。
Worker 类代表一个独立的 JavaScript 执行线程。
大多数 Node.js API 在其中可用。
Worker 环境内的显著差异包括:
process.stdin、process.stdout和process.stderr流可能会被父线程重定向。require('node:worker_threads').isMainThread属性设置为false。require('node:worker_threads').parentPort消息端口可用。process.exit()不会停止整个程序,只会停止单个线程, 且process.abort()不可用。process.chdir()和设置组或用户 ID 的process方法 不可用。process.env是父线程环境变量的副本, 除非另有指定。对一个副本的更改在其他 线程中不可见,并且对原生插件不可见(除非 将worker.SHARE_ENV作为env选项传递给Worker构造函数)。在 Windows 上,与主线程不同, 环境变量的副本以区分大小写的方式运行。process.title不能被修改。- 信号不会通过 [
process.on('...')][Signals events] 交付。 - 由于调用了
worker.terminate(),执行可能在任何点停止。 - 来自父进程的 IPC 通道不可访问。
trace_events模块不受支持。- 原生插件只有在满足 [某些条件][Addons worker support] 的情况下才能从多个线程加载。
可以在其他 Worker 内部创建 Worker 实例。
像 Web Workers 和 node:cluster 模块 一样,双向通信
可以通过线程间消息传递实现。在内部,Worker 拥有一对内置的 MessagePort,
它们在 Worker 创建时已经相互关联。虽然父端
的 MessagePort 对象没有直接暴露,但其功能通过
父线程 Worker 对象上的 worker.postMessage() 和 worker.on('message') 事件
暴露。
要创建自定义消息通道(鼓励使用自定义通道而不是默认
全局通道,因为它有助于关注点分离),用户可以在任一线程上创建
一个 MessageChannel 对象,并通过
预先存在的通道(例如全局通道)将该 MessageChannel 上的
其中一个 MessagePort 传递给另一个线程。
参见 port.postMessage() 以获取有关消息如何传递的更多信息,
以及哪些类型的 JavaScript 值可以成功通过
线程屏障传输。
import assert from 'node:assert';
import {
Worker, MessageChannel, MessagePort, isMainThread, parentPort,
} from 'node:worker_threads';
if (isMainThread) {
const worker = new Worker(new URL(import.meta.url));
const subChannel = new MessageChannel();
worker.postMessage({ hereIsYourPort: subChannel.port1 }, [subChannel.port1]);
subChannel.port2.on('message', (value) => {
console.log('收到:', value);
});
} else {
parentPort.once('message', (value) => {
assert(value.hereIsYourPort instanceof MessagePort);
value.hereIsYourPort.postMessage('worker 正在发送此消息');
value.hereIsYourPort.close();
});
}如果工作线程抛出未捕获的异常,则会发出 'error' 事件。在这种情况下,worker 将被终止。
一旦 worker 停止,就会发出 'exit' 事件。如果 worker
通过调用 process.exit() 退出,exitCode 参数是
传递的退出代码。如果 worker 被终止,exitCode 参数是
1。
这是任何 Worker 实例发出的最后一个事件。
当工作线程调用了
require('node:worker_threads').parentPort.postMessage() 时,会发出 'message' 事件。
参见 port.on('message') 事件以获取更多详情。
所有从工作线程发送的消息都在
Worker 对象上发出 'exit' 事件 之前发出。
当反序列化消息失败时,会发出 'messageerror' 事件。
此方法返回一个 Promise,该 Promise 将解析为与 process.threadCpuUsage() 相同的对象,
如果 worker 不再运行,则拒绝并抛出 ERR_WORKER_NOT_RUNNING 错误。
此方法允许从实际线程外部观察统计信息。
返回一个可读流,用于获取 Worker 当前状态的 V8 快照。
参见 v8.getHeapSnapshot() 以获取更多详情。
如果 Worker 线程不再运行(这可能发生在
['exit' 事件][] 发出之前),返回的 Promise 将立即 被 [ERR_WORKER_NOT_RUNNING`][] 错误拒绝。
此方法返回一个 Promise,该 Promise 将解析为与 v8.getHeapStatistics() 相同的对象,
如果 worker 不再运行,则拒绝并抛出 ERR_WORKER_NOT_RUNNING 错误。
此方法允许从实际线程外部观察统计信息。
与 perf_hooks eventLoopUtilization() 相同的调用,但返回的是
worker 实例的值。
一个区别是,与主线程不同,worker 内的引导是在 事件循环内完成的。因此,一旦 worker 的脚本开始执行, 事件循环利用率立即可用。
idle 时间不增加并不表示 worker 卡在引导过程中。以下示例显示 worker 的整个
生命周期从未积累任何 idle 时间,但仍能够处理
消息。
import { Worker, isMainThread, parentPort } from 'node:worker_threads';
if (isMainThread) {
const worker = new Worker(new URL(import.meta.url));
setInterval(() => {
worker.postMessage('hi');
console.log(worker.performance.eventLoopUtilization());
}, 100).unref();
} else {
parentPort.on('message', () => console.log('消息')).unref();
(function r(n) {
if (--n < 0) return;
const t = Date.now();
while (Date.now() - t < 300);
setImmediate(r, n);
})(10);
}Worker 的事件循环利用率仅在发出 'online'
事件 后可用,如果在此之前调用,或在 'exit'
事件 之后调用,则所有属性的值为 0。
发送消息给 worker,该消息通过
require('node:worker_threads').parentPort.on('message') 接收。
参见 port.postMessage() 以获取更多详情。
提供此 Worker 线程的 JS 引擎资源约束集。
如果将 resourceLimits 选项传递给了 Worker 构造函数,
则与此值匹配。
如果 worker 已停止,返回值为一个空对象。
启动 CPU 性能分析,然后返回一个 Promise,该 Promise 兑现为一个错误
或一个 CPUProfileHandle 对象。此 API 支持 await using 语法。
const { Worker } = require('node:worker_threads');
const worker = new Worker(`
const { parentPort } = require('worker_threads');
parentPort.on('message', () => {});
`, { eval: true });
worker.on('online', async () => {
const handle = await worker.startCpuProfile({ sampleInterval: 1 });
const profile = await handle.stop();
console.log(profile);
worker.terminate();
});await using 示例。
const { Worker } = require('node:worker_threads');
const w = new Worker(`
const { parentPort } = require('worker_threads');
parentPort.on('message', () => {});
`, { eval: true });
w.on('online', async () => {
// 返回时自动停止性能分析,且性能分析将被丢弃
await using handle = await w.startCpuProfile();
});启动堆性能分析,然后返回一个 Promise,该 Promise 兑现为一个错误
或一个 HeapProfileHandle 对象。此 API 支持 await using 语法。
const { Worker } = require('node:worker_threads');
const worker = new Worker(`
const { parentPort } = require('worker_threads');
parentPort.on('message', () => {});
`, { eval: true });
worker.on('online', async () => {
const handle = await worker.startHeapProfile();
const profile = await handle.stop();
console.log(profile);
worker.terminate();
});await using 示例。
const { Worker } = require('node:worker_threads');
const w = new Worker(`
const { parentPort } = require('worker_threads');
parentPort.on('message', () => {});
`, { eval: true });
w.on('online', async () => {
// 返回时自动停止性能分析,且性能分析将被丢弃
await using handle = await w.startHeapProfile();
});这是一个可读流,包含在 worker 线程内写入 process.stderr
的数据。如果未将 stderr: true 传递给
Worker 构造函数,则数据会管道传输到父线程的
process.stderr 流。
如果将 stdin: true 传递给了 Worker 构造函数,这是一个
可写流。写入此流的数据将在
worker 线程中作为 process.stdin 可用。
这是一个可读流,包含在 worker 线程内写入 process.stdout
的数据。如果未将 stdout: true 传递给
Worker 构造函数,则数据会管道传输到父线程的
process.stdout 流。
尽快停止 worker 线程中的所有 JavaScript 执行。
返回一个 Promise,用于获取退出代码,当
'exit' 事件 发出时兑现。
引用线程的整数标识符。在 worker 线程内部,
它作为 require('node:worker_threads').threadId 可用。
此值在单个进程内的每个 Worker 实例中是唯一的。
A string identifier for the referenced thread, or null if the thread is not running.
Within the worker thread, it is available as require('node:worker_threads').threadName.
async function example() {
await using worker = new Worker('for (;;) {}', { eval: true });
// 当作用域退出时,Worker 会自动终止。
}