- assert 断言
- async_hooks 异步钩子
- async_hooks/context 异步上下文
- buffer 缓冲区
- C++插件
- C/C++插件(使用Node-API)
- C++嵌入器
- child_process 子进程
- cluster 集群
- CLI 命令行
- console 控制台
- Corepack 核心包
- crypto 加密
- crypto/webcrypto 网络加密
- debugger 调试器
- deprecation 弃用
- dgram 数据报
- diagnostics_channel 诊断通道
- dns 域名服务器
- domain 域
- Error 错误
- events 事件触发器
- fs 文件系统
- global 全局变量
- http 超文本传输协议
- http2 超文本传输协议2.0
- https 安全超文本传输协议
- inspector 检查器
- Intl 国际化
- module 模块
- module/cjs CommonJS模块
- module/esm ECMAScript模块
- module/package 包模块
- net 网络
- os 操作系统
- path 路径
- perf_hooks 性能钩子
- permission 权限
- process 进程
- punycode 域名代码
- querystring 查询字符串
- readline 逐行读取
- repl 交互式解释器
- report 诊断报告
- sea 单个可执行应用程序
- stream 流
- stream/web 网络流
- string_decoder 字符串解码器
- test 测试
- timers 定时器
- tls 安全传输层
- trace_events 跟踪事件
- tty 终端
- url 网址
- util 实用工具
- v8 引擎
- vm 虚拟机
- wasi 网络汇编系统接口
- worker_threads 工作线程
- zlib 压缩
Node.js v18.16.0 文档
- Node.js v18.16.0
-
►
目录
- 工作线程
worker.getEnvironmentData(key)
worker.isMainThread
worker.markAsUntransferable(object)
worker.moveMessagePortToContext(port, contextifiedSandbox)
worker.parentPort
worker.receiveMessageOnPort(port)
worker.resourceLimits
worker.SHARE_ENV
worker.setEnvironmentData(key[, value])
worker.threadId
worker.workerData
- 类:
BroadcastChannel extends EventTarget
- 类:
MessageChannel
- 类:
MessagePort
- 类:
Worker
new Worker(filename[, options])
- 事件:
'error'
- 事件:
'exit'
- 事件:
'message'
- 事件:
'messageerror'
- 事件:
'online'
worker.getHeapSnapshot()
worker.performance
worker.postMessage(value[, transferList])
worker.ref()
worker.resourceLimits
worker.stderr
worker.stdin
worker.stdout
worker.terminate()
worker.threadId
worker.unref()
- 注意事项
- 工作线程
-
►
导航
- assert 断言
- async_hooks 异步钩子
- async_hooks/context 异步上下文
- buffer 缓冲区
- C++插件
- C/C++插件(使用Node-API)
- C++嵌入器
- child_process 子进程
- cluster 集群
- CLI 命令行
- console 控制台
- Corepack 核心包
- crypto 加密
- crypto/webcrypto 网络加密
- debugger 调试器
- deprecation 弃用
- dgram 数据报
- diagnostics_channel 诊断通道
- dns 域名服务器
- domain 域
- Error 错误
- events 事件触发器
- fs 文件系统
- global 全局变量
- http 超文本传输协议
- http2 超文本传输协议2.0
- https 安全超文本传输协议
- inspector 检查器
- Intl 国际化
- module 模块
- module/cjs CommonJS模块
- module/esm ECMAScript模块
- module/package 包模块
- net 网络
- os 操作系统
- path 路径
- perf_hooks 性能钩子
- permission 权限
- process 进程
- punycode 域名代码
- querystring 查询字符串
- readline 逐行读取
- repl 交互式解释器
- report 诊断报告
- sea 单个可执行应用程序
- stream 流
- stream/web 网络流
- string_decoder 字符串解码器
- test 测试
- timers 定时器
- tls 安全传输层
- trace_events 跟踪事件
- tty 终端
- url 网址
- util 实用工具
- v8 引擎
- vm 虚拟机
- wasi 网络汇编系统接口
- worker_threads 工作线程
- zlib 压缩
- ► 其他版本
- 云服务器
目录
- 工作线程
worker.getEnvironmentData(key)
worker.isMainThread
worker.markAsUntransferable(object)
worker.moveMessagePortToContext(port, contextifiedSandbox)
worker.parentPort
worker.receiveMessageOnPort(port)
worker.resourceLimits
worker.SHARE_ENV
worker.setEnvironmentData(key[, value])
worker.threadId
worker.workerData
- 类:
BroadcastChannel extends EventTarget
- 类:
MessageChannel
- 类:
MessagePort
- 类:
Worker
new Worker(filename[, options])
- 事件:
'error'
- 事件:
'exit'
- 事件:
'message'
- 事件:
'messageerror'
- 事件:
'online'
worker.getHeapSnapshot()
worker.performance
worker.postMessage(value[, transferList])
worker.ref()
worker.resourceLimits
worker.stderr
worker.stdin
worker.stdout
worker.terminate()
worker.threadId
worker.unref()
- 注意事项
工作线程#
node:worker_threads
模块允许使用并行执行 JavaScript 的线程。 要访问它:
const worker = require('node:worker_threads');
工作线程对于执行 CPU 密集型的 JavaScript 操作很有用。 它们对 I/O 密集型的工作帮助不大。 Node.js 内置的异步 I/O 操作比工作线程更高效。
与 child_process
或 cluster
不同,worker_threads
可以共享内存。 它们通过传输 ArrayBuffer
实例或共享 SharedArrayBuffer
实例来实现。
const {
Worker, isMainThread, parentPort, workerData,
} = require('node:worker_threads');
if (isMainThread) {
module.exports = function parseJSAsync(script) {
return new Promise((resolve, reject) => {
const worker = new Worker(__filename, {
workerData: script,
});
worker.on('message', resolve);
worker.on('error', reject);
worker.on('exit', (code) => {
if (code !== 0)
reject(new Error(`Worker stopped with exit code ${code}`));
});
});
};
} else {
const { parse } = require('some-js-parsing-library');
const script = workerData;
parentPort.postMessage(parse(script));
}
上面的示例为每个 parseJSAsync()
调用衍生工作线程。 在实践中,为这些类型的任务使用工作线程池。 否则,创建工作线程的开销可能会超过其收益。
当实现工作线程池时,使用 AsyncResource
API 通知诊断工具(例如提供异步的堆栈跟踪)有关任务与其结果之间的相关性。 有关示例实现,请参阅 async_hooks
文档中的 "Using AsyncResource
for a Worker
thread pool"。
默认情况下,工作线程继承非进程特定的选项。 参考 Worker constructor options
了解如何自定义工作线程选项,特别是 argv
和 execArgv
选项。
worker.getEnvironmentData(key)
#
在工作线程中,worker.getEnvironmentData()
返回传给衍生线程的 worker.setEnvironmentData()
的数据的克隆。
每个新的 Worker
都会自动接收到自己的环境数据的副本。
const {
Worker,
isMainThread,
setEnvironmentData,
getEnvironmentData,
} = require('node:worker_threads');
if (isMainThread) {
setEnvironmentData('Hello', 'World!');
const worker = new Worker(__filename);
} else {
console.log(getEnvironmentData('Hello')); // Prints 'World!'.
}
worker.isMainThread
#
如果此代码不在 Worker
线程内运行,则为 true
。
const { Worker, isMainThread } = require('node:worker_threads');
if (isMainThread) {
// This re-loads the current file inside a Worker instance.
new Worker(__filename);
} else {
console.log('Inside Worker!');
console.log(isMainThread); // Prints 'false'.
}
worker.markAsUntransferable(object)
#
将对象标记为不可传输。 如果 object
出现在 port.postMessage()
调用的传输列表中,则忽略它。
特别是,这对于可以克隆而不是传输的对象,以及被发送方的其他对象使用的对象来说是有意义的。
例如,Node.js 将 ArrayBuffer
用于 Buffer
pool 标记。
此操作无法撤消。
const { MessageChannel, markAsUntransferable } = require('node:worker_threads');
const pooledBuffer = new ArrayBuffer(8);
const typedArray1 = new Uint8Array(pooledBuffer);
const typedArray2 = new Float64Array(pooledBuffer);
markAsUntransferable(pooledBuffer);
const { port1 } = new MessageChannel();
port1.postMessage(typedArray1, [ typedArray1.buffer ]);
// The following line prints the contents of typedArray1 -- it still owns
// its memory and has been cloned, not transferred. Without
// `markAsUntransferable()`, this would print an empty Uint8Array.
// typedArray2 is intact as well.
console.log(typedArray1);
console.log(typedArray2);
浏览器中没有与此 API 等效的 API。
worker.moveMessagePortToContext(port, contextifiedSandbox)
#
-
port
<MessagePort> 要传输的消息端口。 -
contextifiedSandbox
<Object>vm.createContext()
方法返回的 contextified 对象。 -
返回: <MessagePort>
将 MessagePort
传输到不同的 vm
上下文 原始的 port
对象变得不可用,返回的 MessagePort
实例取而代之。
返回的 MessagePort
是目标上下文中的对象,并且继承自其全局的 Object
类。 传给 port.onmessage()
监听器的对象也在目标上下文中创建并且从其全局的 Object
类继承。
但是,创建的 MessagePort
不再继承 EventTarget
,只有 port.onmessage()
可以使用它来接收事件。
worker.parentPort
#
如果此线程是 Worker
,则这是允许与父线程通信的 MessagePort
。 使用 parentPort.postMessage()
发送的消息在使用 worker.on('message')
的父线程中可用,使用 worker.postMessage()
从父线程发送的消息在使用 parentPort.on('message')
的该线程中可用。
const { Worker, isMainThread, parentPort } = require('node:worker_threads');
if (isMainThread) {
const worker = new Worker(__filename);
worker.once('message', (message) => {
console.log(message); // Prints 'Hello, world!'.
});
worker.postMessage('Hello, world!');
} else {
// When a message from the parent thread is received, send it back:
parentPort.once('message', (message) => {
parentPort.postMessage(message);
});
}
worker.receiveMessageOnPort(port)
#
-
port
<MessagePort> | <BroadcastChannel> -
返回: <Object> | <undefined>
从给定的 MessagePort
接收消息。 如果没有消息可用,则返回 undefined
,否则返回具有单个 message
属性的对象,该对象包含消息负载,对应于 MessagePort
队列中最旧的消息。
const { MessageChannel, receiveMessageOnPort } = require('node:worker_threads');
const { port1, port2 } = new MessageChannel();
port1.postMessage({ hello: 'world' });
console.log(receiveMessageOnPort(port2));
// Prints: { message: { hello: 'world' } }
console.log(receiveMessageOnPort(port2));
// Prints: undefined
当使用此函数时,不会触发 'message'
事件,也不会调用 onmessage
监听器。
worker.resourceLimits
#
在这个工作线程中提供了一组 JS 引擎资源约束。
如果将 resourceLimits
选项传给 Worker
构造函数,则这与其值匹配。
如果在主线程中使用此,则其值为空对象。
worker.SHARE_ENV
#
可以作为 Worker
构造函数的 env
选项传入的特殊值,表示当前线程和工作线程应该共享对同一组环境变量的读写访问。
const { Worker, SHARE_ENV } = require('node:worker_threads');
new Worker('process.env.SET_IN_WORKER = "foo"', { eval: true, env: SHARE_ENV })
.on('exit', () => {
console.log(process.env.SET_IN_WORKER); // Prints 'foo'.
});
worker.setEnvironmentData(key[, value])
#
key
<any> 任何可以用作 <Map> 键的任意、可克隆的 JavaScript 值。value
<any> 任何任意的、可克隆的 JavaScript 值都将被克隆并自动传给所有新的Worker
实例。 如果value
作为undefined
传入,则key
之前设置的任何值都将被删除。
worker.setEnvironmentData()
API 设置当前线程中 worker.getEnvironmentData()
的内容以及从当前上下文产生的所有新 Worker
实例。
worker.threadId
#
当前线程的整数标识符。 在对应的工作线程对象上(如果有的话),可以作为 worker.threadId
使用。
此值对于单个进程中的每个 Worker
实例都是唯一的。
worker.workerData
#
任意的 JavaScript 值,其中包含传给该线程的 Worker
构造函数的数据的克隆。
根据 HTML 结构化克隆算法,数据被克隆,就像使用 postMessage()
一样。
const { Worker, isMainThread, workerData } = require('node:worker_threads');
if (isMainThread) {
const worker = new Worker(__filename, { workerData: 'Hello, world!' });
} else {
console.log(workerData); // Prints 'Hello, world!'.
}
类:BroadcastChannel extends EventTarget
#
BroadcastChannel
的实例允许与绑定到相同通道名称的所有其他 BroadcastChannel
实例进行异步的一对多通信。
'use strict';
const {
isMainThread,
BroadcastChannel,
Worker,
} = require('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(__filename);
} else {
bc.postMessage('hello from every worker');
bc.close();
}
new BroadcastChannel(name)
#
name
<any> 要连接的通道名称。 任何可以使用`${name}`
转换为字符串的 JavaScript 值都是允许的。
broadcastChannel.close()
#
关闭 BroadcastChannel
连接。
broadcastChannel.onmessage
#
- 类型: <Function> 当接收到消息时,使用单个
MessageEvent
参数调用。
broadcastChannel.onmessageerror
#
- 类型: <Function> 使用接收到的消息调用不能反序列化。
broadcastChannel.postMessage(message)
#
message
<any> 任何可克隆的 JavaScript 值。
broadcastChannel.ref()
#
unref()
的相反。 如果它是唯一剩下的活动句柄(默认行为),则在先前 unref()
ed BroadcastChannel 上调用 ref()
不会让程序退出。 如果端口是 ref()
的,则再次调用 ref()
没有效果。
broadcastChannel.unref()
#
如果这是事件系统中唯一的活动句柄,则在广播通道上调用 unref()
允许线程退出。 如果广播通道已经 unref()
,则再次调用 unref()
无效。
类:MessageChannel
#
worker.MessageChannel
类的实例代表异步的双向通信通道。
MessageChannel
没有自己的方法。 new MessageChannel()
产生具有 port1
和 port2
属性的对象,其引用链接的 MessagePort
实例。
const { MessageChannel } = require('node:worker_threads');
const { port1, port2 } = new MessageChannel();
port1.on('message', (message) => console.log('received', message));
port2.postMessage({ foo: 'bar' });
// Prints: received { foo: 'bar' } from the `port1.on('message')` listener
类:MessagePort
#
- 继承: <EventTarget>
worker.MessagePort
类的实例代表异步双向通信通道的一端。 它可以用来在不同的Worker
之间传输结构化数据、内存区域和其他MessagePort
。
此实现匹配 浏览器MessagePort
。
事件:'close'
#
一旦通道的任一侧断开连接,则会触发 'close'
事件。
const { MessageChannel } = require('node:worker_threads');
const { port1, port2 } = new MessageChannel();
// Prints:
// foobar
// closed!
port2.on('message', (message) => console.log(message));
port2.on('close', () => console.log('closed!'));
port1.postMessage('foobar');
port1.close();
事件:'message'
#
value
<any> 传输值
为任何传入消息触发 'message'
事件,其中包含 port.postMessage()
的克隆输入。
此事件的监听器接收传给 postMessage()
的 value
参数的副本,没有其他参数。
事件:'messageerror'
#
error
<Error> 错误对象
当反序列化消息失败时,则会触发 'messageerror'
事件。
目前,当在接收端实例化已发布的 JS 对象时发生错误时,则会触发此事件。 这种情况很少见,但可能会发生,例如,当某些 Node.js API 对象在 vm.Context
中接收到时(Node.js API 当前不可用)。
port.close()
#
禁止在连接的任一端进一步发送消息。
当此 MessagePort
上不会发生进一步的通信时,可以调用此方法。
'close'
事件 在作为通道一部分的两个 MessagePort
实例上触发。
port.postMessage(value[, transferList])
#
value
<any>transferList
<Object[]>
向该通道的接收端发送 JavaScript 值。
value
以与 HTML 结构化克隆算法 兼容的方式传输。
特别是与 JSON
的显着区别是:
value
可能包含循环引用。value
可能包含内置 JS 类型的实例,例如RegExp
、BigInt
、Map
、Set
等。value
可能包含类型化数组,同时使用ArrayBuffer
和SharedArrayBuffer
。value
可能包含WebAssembly.Module
实例。value
可能不包含原生 (C++ 支持) 对象,除了:
const { MessageChannel } = require('node:worker_threads');
const { port1, port2 } = new MessageChannel();
port1.on('message', (message) => console.log(message));
const circularData = {};
circularData.foo = circularData;
// Prints: { foo: [Circular] }
port2.postMessage(circularData);
transferList
可能是 ArrayBuffer
、MessagePort
和 FileHandle
对象的列表。
传输后,它们在通道的发送端不再可用(即使它们不包含在 value
中)。 与 子进程 不同,目前不支持传输句柄,例如网络套接字。
如果 value
包含 SharedArrayBuffer
实例,则可以从任一线程访问它们。 它们不能在 transferList
中列出。
value
可能仍然包含不在 transferList
中的 ArrayBuffer
个实例; 在这种情况下,底层内存被复制而不是移动。
const { MessageChannel } = require('node:worker_threads');
const { port1, port2 } = new MessageChannel();
port1.on('message', (message) => console.log(message));
const uint8Array = new Uint8Array([ 1, 2, 3, 4 ]);
// This posts a copy of `uint8Array`:
port2.postMessage(uint8Array);
// This does not copy data, but renders `uint8Array` unusable:
port2.postMessage(uint8Array, [ uint8Array.buffer ]);
// The memory for the `sharedUint8Array` is accessible from both the
// original and the copy received by `.on('message')`:
const sharedUint8Array = new Uint8Array(new SharedArrayBuffer(4));
port2.postMessage(sharedUint8Array);
// This transfers a freshly created message port to the receiver.
// This can be used, for example, to create communication channels between
// multiple `Worker` threads that are children of the same parent thread.
const otherChannel = new MessageChannel();
port2.postMessage({ port: otherChannel.port1 }, [ otherChannel.port1 ]);
消息对象立即克隆,发布后可修改,无副作用。
有关此 API 背后的序列化和反序列化机制的更多信息,请参阅 node:v8
模块的序列化 API。
传输 TypedArray 和缓冲区时的注意事项#
所有 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); // prints 5
port.postMessage(u1, [u1.buffer]);
console.log(u2.length); // prints 0
对于 Buffer
实例,具体来说,底层 ArrayBuffer
是否可以被传输或克隆完全取决于实例是如何创建的,这通常无法可靠地确定。
ArrayBuffer
可以用 markAsUntransferable()
标记来表示它应该总是被克隆并且永远不会被传输。
根据 Buffer
实例的创建方式,它可能拥有也可能不拥有其底层 ArrayBuffer
。 除非知道 Buffer
实例拥有它,否则不得传输 ArrayBuffer
。 特别是,对于从内部 Buffer
池(例如使用 Buffer.from()
或 Buffer.allocUnsafe()
)创建的 Buffer
,传输它们是不可能的,它们总是被克隆,这会发送整个 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 4; }
}
const { port1, port2 } = new MessageChannel();
port1.onmessage = ({ data }) => console.log(data);
port2.postMessage(new Foo());
// Prints: { c: 3 }
此限制扩展到许多内置对象,例如全局的 URL
对象:
const { port1, port2 } = new MessageChannel();
port1.onmessage = ({ data }) => console.log(data);
port2.postMessage(new URL('https://example.org'));
// Prints: { }
port.hasRef()
#
- 返回: <boolean>
如果为 true,则 MessagePort
对象将使 Node.js 事件循环保持活动状态。
port.ref()
#
unref()
的相反。 如果它是唯一剩下的活动句柄(默认行为),则在以前的 unref()
ed 端口上调用 ref()
不会让程序退出。 如果端口是 ref()
的,则再次调用 ref()
没有效果。
如果使用 .on('message')
绑定或删除监听器,则根据事件的监听器是否存在,端口将自动进行 ref()
和 unref()
。
port.start()
#
开始在此 MessagePort
上接收消息。 当将此端口用作事件触发器时,一旦绑定了 'message'
监听器,则会自动调用它
此方法与 Web MessagePort
API 相同。 在 Node.js 中,只有在没有事件监听器时才用于忽略消息。
Node.js 在处理 .onmessage
方面也有分歧。 设置它会自动调用 .start()
,但取消设置它会让消息排队,直到设置新的处理程序或端口被丢弃。
port.unref()
#
如果这是事件系统中唯一的活动句柄,则在端口上调用 unref()
允许线程退出。 如果端口已经 unref()
,则再次调用 unref()
无效。
如果使用 .on('message')
绑定或删除监听器,则根据事件的监听器是否存在,端口将自动进行 ref()
和 unref()
。
类:Worker
#
- 继承: <EventEmitter>
Worker
类代表独立的 JavaScript 执行线程。
大多数 Node.js API 都可以在其中使用。
工作线程环境中的显着差异是:
process.stdin
、process.stdout
、process.stderr
流可能被父线程重定向。require('node:worker_threads').isMainThread
属性被设置为false
。require('node:worker_threads').parentPort
消息端口可用。process.exit()
不会停止整个程序,只是单个线程,且process.abort()
不可用。- 设置群组或用户标识的
process.chdir()
和process
方法不可用。 process.env
是父线程的环境变量的副本,除非另有说明。 对副本的更改在其他线程中不可见,且对原生插件不可见(除非将worker.SHARE_ENV
作为env
选项传给Worker
构造函数)。process.title
不能修改。- 信号不通过
process.on('...')
传送。 worker.terminate()
被调用时,执行可能在任何时候停止。- 来自父进程的进程间通信通道不可访问。
- 不支持
trace_events
模块。 - 如果原生附加组件满足 特定条件,则只能从多个线程加载。
在其他 Worker
中创建 Worker
实例是可能的。
与网络工作线程和node:cluster
模块一样,可以通过线程间消息传递实现双向通信。 在内部,Worker
有一对内置的 MessagePort
,它们在创建 Worker
时已经相互关联。 虽然父端的 MessagePort
对象没有直接暴露,但其功能通过父线程 Worker
对象上的 worker.postMessage()
和 worker.on('message')
事件暴露。
要创建自定义消息通道(鼓励使用默认全局通道,因为它有助于分离关注点),用户可以在任一线程上创建 MessageChannel
对象,并通过预先存在的线程将 MessageChannel
上的 MessagePort
之一传递给另一个线程 通道,例如全局通道。
有关如何传递消息以及可以成功通过线程屏障传输的 JavaScript 值类型的更多信息,请参阅 port.postMessage()
。
const assert = require('node:assert');
const {
Worker, MessageChannel, MessagePort, isMainThread, parentPort,
} = require('node:worker_threads');
if (isMainThread) {
const worker = new Worker(__filename);
const subChannel = new MessageChannel();
worker.postMessage({ hereIsYourPort: subChannel.port1 }, [subChannel.port1]);
subChannel.port2.on('message', (value) => {
console.log('received:', value);
});
} else {
parentPort.once('message', (value) => {
assert(value.hereIsYourPort instanceof MessagePort);
value.hereIsYourPort.postMessage('the worker is sending this');
value.hereIsYourPort.close();
});
}
new Worker(filename[, options])
#
filename
<string> | <URL> 工作线程的主脚本或模块的路径。 必须是以./
或../
开头的绝对路径或相对路径(即相对于当前工作目录)、或者是使用file:
或data:
协议的 WHATWGURL
对象 使用data:
网址 时,将使用 ECMAScript 模块加载器 根据 MIME 类型解释数据。 如果options.eval
是true
,则这是包含 JavaScript 代码(而不是路径)的字符串。options
<Object>argv
<any[]> 将被字符串化并附加到工作线程中的process.argv
的参数列表。 这与workerData
非常相似,但这些值在全局的process.argv
上可用,就好像它们作为 CLI 选项传给脚本一样。env
<Object> 如果设置,则指定工作线程内process.env
的初始值。worker.SHARE_ENV
作为一个特殊的值,可以用来指定父线程和子线程共享环境变量; 在这种情况下,对一个线程的process.env
对象的更改也会影响另一个线程。 默认值:process.env
。eval
<boolean> 如果true
并且第一个参数是string
,则将构造函数的第一个参数解释为一旦工作线程在线就执行的脚本。execArgv
<string[]> 传给工作线程的 node CLI 选项的列表。 不支持 V8 选项(如--max-old-space-size
)和影响进程的选项(如--title
)。 如果设置,则此在工作线程内部作为process.execArgv
提供。 默认情况下,选项继承自父线程。stdin
<boolean> 如果设置为true
,则worker.stdin
提供其内容在工作线程中显示为process.stdin
的可写流。 默认情况下,不提供任何数据。stdout
<boolean> 如果设置为true
,则worker.stdout
不会自动通过管道传输到父线程中的process.stdout
。stderr
<boolean> 如果设置为true
,则worker.stderr
不会自动通过管道传输到父线程中的process.stderr
。workerData
<any> 任何被克隆并作为require('node:worker_threads').workerData
可用的 JavaScript 值。 克隆如 HTML 结构化克隆算法 中所述发生,如果无法克隆对象(例如,因为它包含function
),则会抛出错误。trackUnmanagedFds
<boolean> 如果设置为true
,则工作线程会跟踪通过fs.open()
和fs.close()
管理的原始文件描述符,并在工作线程退出时关闭它们,类似于网络套接字或通过FileHandle
API 管理的文件描述符等其他资源。 所有嵌套的Worker
都会自动继承此选项。 默认值:true
。transferList
<Object[]> 如果在workerData
中传入一个或多个类似MessagePort
的对象,则这些条目需要transferList
或抛出ERR_MISSING_MESSAGE_PORT_IN_TRANSFER_LIST
。 有关详细信息,请参阅port.postMessage()
。resourceLimits
<Object> 新的 JS 引擎实例的一组可选资源限制。 达到这些限制会导致Worker
实例终止。 这些限制只影响 JS 引擎,不影响外部数据,包括没有ArrayBuffer
。 即使设置了这些限制,如果遇到全局内存不足的情况,进程仍可能会中止。maxOldGenerationSizeMb
<number> 主堆的最大大小 (以 MB 为单位)。 如果设置了命令行参数--max-old-space-size
,它将覆盖此设置。maxYoungGenerationSizeMb
<number> 最近创建的对象的最大堆空间大小。 如果设置了命令行参数--max-semi-space-size
,它将覆盖此设置。codeRangeSizeMb
<number> 用于生成代码的预分配内存范围的大小。stackSizeMb
<number> 线程的默认最大堆栈大小。 较小的值可能会导致工作线程实例无法使用。 默认值:4
。
name
<string> 一个可选的name
附加到工作人员标头用于调试/识别目的,使最终标头为[worker ${id}] ${name}
。 默认值:''
。
事件:'error'
#
err
<Error>
如果工作线程抛出未捕获的异常,则会触发 'error'
事件。 在这种情况下,工作线程被终止。
事件:'exit'
#
exitCode
<integer>
一旦工作线程停止,则会触发 'exit'
事件。 如果工作线程是通过调用 process.exit()
退出的,则 exitCode
参数就是传入的退出码。 如果工作线程被终止,则 exitCode
参数为 1
。
这是任何 Worker
实例触发的最终事件。
事件:'message'
#
value
<any> 传输值
当工作线程调用 require('node:worker_threads').parentPort.postMessage()
时,则会触发 'message'
事件。
详情请见 port.on('message')
事件。
在 Worker
对象上触发 'exit'
事件 之前,从工作线程发送的所有消息都会触发。
事件:'messageerror'
#
error
<Error> 错误对象
当反序列化消息失败时,则会触发 'messageerror'
事件。
事件:'online'
#
当工作线程开始执行 JavaScript 代码时,则会触发 'online'
事件。
worker.getHeapSnapshot()
#
- 返回: <Promise> 对包含 V8 堆快照的可读流的 promise
返回工作线程当前状态的 V8 快照的可读流。
有关详细信息,请参阅 v8.getHeapSnapshot()
。
如果 Worker 线程不再运行,这可能会发生之前的 'exit'
事件 is emitted, the returned Promise
is rejected
immediately with an ERR_WORKER_NOT_RUNNING
错误。
worker.performance
#
可用于从工作线程实例查询性能信息的对象。 类似于perf_hooks.performance
。
performance.eventLoopUtilization([utilization1[, utilization2]])
#
utilization1
<Object> 上一次调用eventLoopUtilization()
的结果。utilization2
<Object> 在utilization1
之前调用eventLoopUtilization()
的结果。- 返回 <Object>
与 perf_hooks
eventLoopUtilization()
相同的调用,除了返回 worker 实例的值。
一个区别是,与主线程不同,工作线程内的引导是在事件循环内完成的。 因此,一旦工作线程的脚本开始执行,事件循环的利用率将立即可用。
不增加的 idle
时间并不表示工作线程卡在引导中。 下面的示例展示了工作线程的整个生命周期从未累积任何 idle
时间,但仍然能够处理消息。
const { Worker, isMainThread, parentPort } = require('node:worker_threads');
if (isMainThread) {
const worker = new Worker(__filename);
setInterval(() => {
worker.postMessage('hi');
console.log(worker.performance.eventLoopUtilization());
}, 100).unref();
return;
}
parentPort.on('message', () => console.log('msg')).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.postMessage(value[, transferList])
#
value
<any>transferList
<Object[]>
向通过 require('node:worker_threads').parentPort.on('message')
接收到的工作线程发送消息。
有关详细信息,请参阅 port.postMessage()
。
worker.ref()
#
与 unref()
相反,如果它是唯一剩下的活动句柄(默认行为),则在之前 unref()
ed worker 上调用 ref()
不会让程序退出。 如果工作线程是 ref()
的,则再次调用 ref()
没有效果。
worker.resourceLimits
#
为此工作线程提供了一组 JS 引擎资源约束。
如果将 resourceLimits
选项传给 Worker
构造函数,则这与其值匹配。
如果工作线程已经停止,则返回值是空对象。
worker.stderr
#
这是包含工作线程内写入 process.stderr
的数据的可读流。 如果 stderr: true
没有传给 Worker
构造函数,则数据将通过管道传输到父线程的 process.stderr
流。
worker.stdin
#
如果将 stdin: true
传给 Worker
构造函数,则这是可写流。 写入此流的数据将在工作线程中作为 process.stdin
可用。
worker.stdout
#
这是包含工作线程内写入 process.stdout
的数据的可读流。 如果 stdout: true
没有传给 Worker
构造函数,则数据将通过管道传输到父线程的 process.stdout
流。
worker.terminate()
#
- 返回: <Promise>
尽快停止工作线程中的所有 JavaScript 执行。
返回在触发 'exit'
事件 时完成的退出代码的 Promise。
worker.threadId
#
引用线程的整数标识符。 在工作线程内部,它作为 require('node:worker_threads').threadId
可用。
此值对于单个进程中的每个 Worker
实例都是唯一的。
worker.unref()
#
如果这是事件系统中唯一的活动句柄,则在工作线程上调用 unref()
允许线程退出。 如果工作线程已经 unref()
,则再次调用 unref()
无效。
注意事项#
stdio 的同步阻塞#
Worker
利用通过 <MessagePort> 传递的消息来实现与 stdio
的交互。 这意味着来自 Worker
的 stdio
输出可能会被接收端的同步代码阻塞,这会阻塞 Node.js 事件循环。
import {
Worker,
isMainThread,
} from 'worker_threads';
if (isMainThread) {
new Worker(new URL(import.meta.url));
for (let n = 0; n < 1e10; n++) {
// Looping to simulate work.
}
} else {
// This output will be blocked by the for loop in the main thread.
console.log('foo');
}
'use strict';
const {
Worker,
isMainThread,
} = require('node:worker_threads');
if (isMainThread) {
new Worker(__filename);
for (let n = 0; n < 1e10; n++) {
// Looping to simulate work.
}
} else {
// This output will be blocked by the for loop in the main thread.
console.log('foo');
}
从预加载脚本启动工作线程#
从预加载脚本(使用 -r
命令行标志加载和运行的脚本)启动工作线程时要小心。 除非显式设置了 execArgv
选项,否则新的工作线程会自动从正在运行的进程继承命令行标志,并将预加载与主线程相同的预加载脚本。 如果预加载脚本无条件地启动工作线程,则每个衍生的线程都会衍生另一个直到应用程序崩溃。