Node.js v25.0.0 文档
- Node.js v25.0.0
-
目录
- 工作线程
worker_threads.getEnvironmentData(key)
worker_threads.isInternalThread
worker_threads.isMainThread
worker_threads.markAsUntransferable(object)
worker_threads.isMarkedAsUntransferable(object)
worker_threads.markAsUncloneable(object)
worker_threads.moveMessagePortToContext(port, contextifiedSandbox)
worker_threads.parentPort
worker_threads.postMessageToThread(threadId, value[, transferList][, timeout])
worker_threads.receiveMessageOnPort(port)
worker_threads.resourceLimits
worker_threads.SHARE_ENV
worker_threads.setEnvironmentData(key[, value])
worker_threads.threadId
worker_threads.threadName
worker_threads.workerData
worker_threads.locks
- 类:
BroadcastChannel extends EventTarget
- 类:
MessageChannel
- 类:
MessagePort
- 类:
Worker
new Worker(filename[, options])
- 事件:
'error'
- 事件:
'exit'
- 事件:
'message'
- 事件:
'messageerror'
- 事件:
'online'
worker.cpuUsage([prev])
worker.getHeapSnapshot([options])
worker.getHeapStatistics()
worker.performance
worker.postMessage(value[, transferList])
worker.ref()
worker.resourceLimits
worker.startCpuProfile()
worker.startHeapProfile()
worker.stderr
worker.stdin
worker.stdout
worker.terminate()
worker.threadId
worker.threadName
worker.unref()
worker[Symbol.asyncDispose]()
- 注意
- 工作线程
-
索引
- 断言测试
- 异步上下文跟踪
- 异步钩子
- 缓冲区
- C++ 插件
- 使用 Node-API 的 C/C++ 插件
- C++ 嵌入器 API
- 子进程
- 集群
- 命令行选项
- 控制台
- 加密
- 调试器
- 已弃用的 API
- 诊断通道
- DNS
- 域
- 环境变量
- 错误
- 事件
- 文件系统
- 全局对象
- HTTP
- HTTP/2
- HTTPS
- 检查器
- 国际化
- 模块:CommonJS 模块
- 模块:ECMAScript 模块
- 模块:
node:module
API - 模块:包
- 模块:TypeScript
- 网络
- 操作系统
- 路径
- 性能钩子
- 权限
- 进程
- Punycode
- 查询字符串
- 逐行读取
- REPL
- 报告
- 单一可执行文件应用
- SQLite
- 流
- 字符串解码器
- 测试运行器
- 定时器
- TLS/SSL
- 跟踪事件
- TTY
- UDP/数据报
- URL
- 实用工具
- V8
- 虚拟机
- WASI
- Web Crypto API
- Web Streams API
- 工作线程
- Zlib
- 其他版本
- 选项
工作线程#
node:worker_threads
模块允许使用并行执行 JavaScript 的线程。要访问它:
import worker_threads from 'node:worker_threads';
'use strict';
const worker_threads = require('node:worker_threads');
工作线程(Worker)对于执行 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.on('error', reject);
worker.on('exit', (code) => {
if (code !== 0)
reject(new Error(`Worker stopped with exit code ${code}`));
});
});
};
'use strict';
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
文档中的“为 Worker
线程池使用 AsyncResource
”。
工作线程默认继承非进程特定的选项。请参阅 Worker 构造函数选项
以了解如何自定义工作线程选项,特别是 argv
和 execArgv
选项。
worker_threads.getEnvironmentData(key)
#
在工作线程内部,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')); // Prints 'World!'.
}
'use strict';
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_threads.isInternalThread
#
- 类型:<boolean>
如果此代码在内部 Worker
线程(例如加载器线程)中运行,则为 true
。
node --experimental-loader ./loader.js main.js
// loader.js
import { isInternalThread } from 'node:worker_threads';
console.log(isInternalThread); // true
// loader.js
'use strict';
const { isInternalThread } = require('node:worker_threads');
console.log(isInternalThread); // true
// main.js
import { isInternalThread } from 'node:worker_threads';
console.log(isInternalThread); // false
// main.js
'use strict';
const { isInternalThread } = require('node:worker_threads');
console.log(isInternalThread); // false
worker_threads.isMainThread
#
- 类型:<boolean>
如果此代码不在 Worker
线程中运行,则为 true
。
import { Worker, isMainThread } from 'node:worker_threads';
if (isMainThread) {
// This re-loads the current file inside a Worker instance.
new Worker(new URL(import.meta.url));
} else {
console.log('Inside Worker!');
console.log(isMainThread); // Prints 'false'.
}
'use strict';
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_threads.markAsUntransferable(object)
#
object
<any> 任何任意的 JavaScript 值。
将一个对象标记为不可传输。如果 object
出现在 port.postMessage()
调用的传输列表中,将抛出一个错误。如果 object
是一个原始值,则此操作为空操作。
特别是,这对于可以被克隆而不是被传输,并且在发送端被其他对象使用的对象很有意义。例如,Node.js 用此方法标记其用于 Buffer
池的 ArrayBuffer
。
此操作无法撤销。
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 {
// This will throw an error, because pooledBuffer is not transferable.
port1.postMessage(typedArray1, [ typedArray1.buffer ]);
} catch (error) {
// error.name === 'DataCloneError'
}
// The following line prints the contents of typedArray1 -- it still owns
// its memory and has not been transferred. Without
// `markAsUntransferable()`, this would print an empty Uint8Array and the
// postMessage call would have succeeded.
// typedArray2 is intact as well.
console.log(typedArray1);
console.log(typedArray2);
'use strict';
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();
try {
// This will throw an error, because pooledBuffer is not transferable.
port1.postMessage(typedArray1, [ typedArray1.buffer ]);
} catch (error) {
// error.name === 'DataCloneError'
}
// The following line prints the contents of typedArray1 -- it still owns
// its memory and has not been transferred. Without
// `markAsUntransferable()`, this would print an empty Uint8Array and the
// postMessage call would have succeeded.
// typedArray2 is intact as well.
console.log(typedArray1);
console.log(typedArray2);
浏览器中没有与此 API 等效的功能。
worker_threads.isMarkedAsUntransferable(object)
#
检查一个对象是否已使用 markAsUntransferable()
标记为不可传输。
import { markAsUntransferable, isMarkedAsUntransferable } from 'node:worker_threads';
const pooledBuffer = new ArrayBuffer(8);
markAsUntransferable(pooledBuffer);
isMarkedAsUntransferable(pooledBuffer); // Returns true.
'use strict';
const { markAsUntransferable, isMarkedAsUntransferable } = require('node:worker_threads');
const pooledBuffer = new ArrayBuffer(8);
markAsUntransferable(pooledBuffer);
isMarkedAsUntransferable(pooledBuffer); // Returns true.
浏览器中没有与此 API 等效的功能。
worker_threads.markAsUncloneable(object)
#
object
<any> 任何任意的 JavaScript 值。
将一个对象标记为不可克隆。如果 object
在 port.postMessage()
调用中用作 message
,将抛出一个错误。如果 object
是一个原始值,则此操作为空操作。
这对 ArrayBuffer
或任何类似 Buffer
的对象没有影响。
此操作无法撤销。
import { markAsUncloneable } from 'node:worker_threads';
const anyObject = { foo: 'bar' };
markAsUncloneable(anyObject);
const { port1 } = new MessageChannel();
try {
// This will throw an error, because anyObject is not cloneable.
port1.postMessage(anyObject);
} catch (error) {
// error.name === 'DataCloneError'
}
'use strict';
const { markAsUncloneable } = require('node:worker_threads');
const anyObject = { foo: 'bar' };
markAsUncloneable(anyObject);
const { port1 } = new MessageChannel();
try {
// This will throw an error, because anyObject is not cloneable.
port1.postMessage(anyObject);
} catch (error) {
// error.name === 'DataCloneError'
}
浏览器中没有与此 API 等效的功能。
worker_threads.moveMessagePortToContext(port, contextifiedSandbox)
#
-
port
<MessagePort> 要传输的消息端口。 -
contextifiedSandbox
<Object> 一个由vm.createContext()
方法返回的上下文隔离对象。
将一个 MessagePort
传输到另一个 vm
上下文。原始的 port
对象变得不可用,返回的 MessagePort
实例将取而代之。
返回的 MessagePort
是目标上下文中的一个对象,并继承自其全局 Object
类。传递给 port.onmessage()
监听器的对象也在目标上下文中创建,并继承自其全局 Object
类。
然而,创建的 MessagePort
不再继承自 <EventTarget>,只能使用 port.onmessage()
来接收事件。
worker_threads.parentPort
#
- 类型:<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); // 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);
});
}
'use strict';
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_threads.postMessageToThread(threadId, value[, transferList][, timeout])
#
threadId
<number> 目标线程的 ID。如果线程 ID 无效,将抛出ERR_WORKER_MESSAGING_FAILED
错误。如果目标线程 ID 是当前线程的 ID,将抛出ERR_WORKER_MESSAGING_SAME_THREAD
错误。value
<any> 要发送的值。transferList
<Object[]> 如果在value
中传递了一个或多个类MessagePort
的对象,则需要为这些项目提供一个transferList
,否则会抛出ERR_MISSING_MESSAGE_PORT_IN_TRANSFER_LIST
错误。更多信息请参见port.postMessage()
。timeout
<number> 等待消息传递的毫秒数。默认情况下为undefined
,表示永远等待。如果操作超时,将抛出ERR_WORKER_MESSAGING_TIMEOUT
错误。- 返回:<Promise> 一个 Promise,如果消息被目标线程成功处理,则该 Promise 会被兑现。
向另一个工作线程发送一个值,通过其线程 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;
'use strict';
const process = require('node:process');
const {
postMessageToThread,
threadId,
workerData,
Worker,
} = require('node:worker_threads');
const channel = new BroadcastChannel('sync');
const level = workerData?.level ?? 0;
if (level < 10) {
const worker = new Worker(__filename, {
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();
});
postMessageToThread(0, { message: 'ping' });
}
channel.onmessage = channel.close;
worker_threads.receiveMessageOnPort(port)
#
-
port
<MessagePort> | <BroadcastChannel> -
返回:<Object> | <undefined>
从给定的 MessagePort
接收单条消息。如果没有可用消息,则返回 undefined
,否则返回一个带有名为 message
的单一属性的对象,该属性包含消息的有效负载,对应于 MessagePort
队列中最旧的消息。
import { MessageChannel, receiveMessageOnPort } from '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
'use strict';
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_threads.resourceLimits
#
- 类型:<Object>
提供此工作线程内部的 JS 引擎资源约束集。如果 resourceLimits
选项已传递给 Worker
构造函数,则此值与其值匹配。
如果在主线程中使用此属性,其值为空对象。
worker_threads.SHARE_ENV
#
- 类型:<symbol>
一个特殊值,可以作为 Worker
构造函数的 env
选项传递,以表明当前线程和工作线程应共享对同一组环境变量的读写访问权限。
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 })
.on('exit', () => {
console.log(process.env.SET_IN_WORKER); // Prints 'foo'.
});
'use strict';
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_threads.setEnvironmentData(key[, value])
#
key
<any> 任何可用作 <Map> 键的任意、可克隆的 JavaScript 值。value
<any> 任何任意的、可克隆的 JavaScript 值,它将被克隆并自动传递给所有新的Worker
实例。如果value
作为undefined
传递,则将删除之前为key
设置的任何值。
worker.setEnvironmentData()
API 设置当前线程和从当前上下文派生的所有新 Worker
实例中 worker.getEnvironmentData()
的内容。
worker_threads.threadId
#
- 类型:<integer>
当前线程的整数标识符。在相应的工作线程对象上(如果有),它作为 worker.threadId
可用。此值对于单个进程内的每个 Worker
实例都是唯一的。
worker_threads.threadName
#
当前线程的字符串标识符,如果线程未运行则为 null。在相应的工作线程对象上(如果有),它作为 worker.threadName
可用。
worker_threads.workerData
#
一个任意的 JavaScript 值,其中包含传递给该线程的 Worker
构造函数的数据的克隆。
数据是根据 HTML 结构化克隆算法,如同使用 postMessage()
一样被克隆的。
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); // Prints 'Hello, world!'.
}
'use strict';
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!'.
}
worker_threads.locks
#
一个 LockManager
实例,可用于协调对同一进程内多个线程可能共享的资源的访问。该 API 模仿了 浏览器 LockManager
的语义。
类:Lock
#
Lock
接口提供有关通过 locks.request()
授予的锁的信息。
类:LockManager
#
LockManager
接口提供了请求和内省锁的方法。要获取一个 LockManager
实例,请使用:
import { locks } from 'node:worker_threads';
'use strict';
const { locks } = require('node:worker_threads');
此实现与 浏览器 LockManager
API 匹配。
locks.request(name[, options], callback)
#
name
<string>options
<Object>mode
<string> 可以是'exclusive'
或'shared'
。默认值:'exclusive'
。ifAvailable
<boolean> 如果为true
,则仅当锁未被持有时才会授予请求。如果无法授予,callback
将以null
而非Lock
实例被调用。默认值:false
。steal
<boolean> 如果为true
,则任何同名的现有锁都将被释放,并且请求会立即被授予,抢占任何排队的请求。默认值:false
。signal
<AbortSignal> 可用于中止一个待处理(但尚未授予)的锁请求。
callback
<Function> 在锁被授予后(或者如果ifAvailable
为true
且锁不可用时,立即以null
调用)被调用一次。当函数返回时,锁会自动释放;或者——如果函数返回一个 promise——当该 promise 解决时释放。- 返回:<Promise> 在锁被释放后解析。
import { locks } from 'node:worker_threads';
await locks.request('my_resource', async (lock) => {
// The lock has been acquired.
});
// The lock has been released here.
'use strict';
const { locks } = require('node:worker_threads');
locks.request('my_resource', async (lock) => {
// The lock has been acquired.
}).then(() => {
// The lock has been released here.
});
locks.query()
#
- 返回:<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}`);
}
'use strict';
const { locks } = require('node:worker_threads');
locks.query().then((snapshot) => {
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 extends EventTarget
#
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();
}
'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();
}
broadcastChannel.close()
#
关闭 BroadcastChannel
连接。
broadcastChannel.onmessage
#
- 类型:<Function> 当收到消息时,以单个
MessageEvent
参数调用。
broadcastChannel.onmessageerror
#
- 类型:<Function> 当接收到的消息无法反序列化时调用。
broadcastChannel.ref()
#
与 unref()
相反。在一个先前被 unref()
的 BroadcastChannel 上调用 ref()
并*不*会让程序在它是唯一活动句柄的情况下退出(默认行为)。如果端口已经被 ref()
,再次调用 ref()
没有效果。
broadcastChannel.unref()
#
在一个 BroadcastChannel 上调用 unref()
允许线程在它是事件系统中唯一活动句柄时退出。如果 BroadcastChannel 已经被 unref()
,再次调用 unref()
没有效果。
类:MessageChannel
#
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' });
// Prints: received { foo: 'bar' } from the `port1.on('message')` listener
'use strict';
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
#
worker.MessagePort
类的实例代表一个异步、双向通信通道的一端。它可以用来在不同的 Worker
之间传输结构化数据、内存区域和其他 MessagePort
。
此实现与浏览器 MessagePort
匹配。
事件:'close'
#
一旦通道的任何一方断开连接,就会发出 'close'
事件。
import { MessageChannel } from '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();
'use strict';
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 对象时发生错误,会发出此事件。这种情况很少见,但可能会发生,例如,当在 vm.Context
中接收到某些 Node.js API 对象时(目前 Node.js API 在其中不可用)。
port.close()
#
禁用连接双方进一步发送消息。当不再通过此 MessagePort
进行通信时,可以调用此方法。
在作为通道一部分的两个 MessagePort
实例上都会发出 'close'
事件。
port.postMessage(value[, transferList])
#
value
<any>transferList
<Object[]>
向此通道的接收方发送一个 JavaScript 值。value
的传输方式与 HTML 结构化克隆算法兼容。
特别是,与 JSON
的显著区别是:
value
可能包含循环引用。value
可能包含内置 JS 类型的实例,如RegExp
s、BigInt
s、Map
s、Set
s 等。value
可能包含类型化数组,包括使用ArrayBuffer
和SharedArrayBuffer
的情况。value
可能包含WebAssembly.Module
实例。value
可能不包含除以下之外的本地(C++-backed)对象:
import { MessageChannel } from '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);
'use strict';
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
实例;在这种情况下,底层内存会被复制而不是移动。
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 ]);
// 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 ]);
'use strict';
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 和 Buffer 时的注意事项#
所有 <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
(例如使用 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 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.ref()
#
与 unref()
相反。在一个先前被 unref()
的端口上调用 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 在其中都可用。
在 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('...')
传递。 - 执行可能因调用
worker.terminate()
而在任何时候停止。 - 无法访问来自父进程的 IPC 通道。
- 不支持
trace_events
模块。 - 原生插件只有在满足特定条件的情况下才能从多个线程加载。
可以在其他 Worker
内部创建 Worker
实例。
与 Web Workers 和 node:cluster
模块一样,可以通过线程间消息传递实现双向通信。在内部,一个 Worker
有一对内置的 MessagePort
,在 Worker
创建时就已经相互关联。虽然父端的 MessagePort
对象没有直接暴露,但其功能通过 worker.postMessage()
和父线程 Worker
对象上的 worker.on('message')
事件暴露出来。
要创建自定义的消息通道(鼓励使用,因为它有助于关注点分离),用户可以在任一线程上创建一个 MessageChannel
对象,并通过一个预先存在的通道(如全局通道)将该 MessageChannel
上的一个 MessagePort
传递给另一个线程。
有关消息如何传递以及哪些类型的 JavaScript 值可以成功地跨越线程屏障的更多信息,请参阅 port.postMessage()
。
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('received:', value);
});
} else {
parentPort.once('message', (value) => {
assert(value.hereIsYourPort instanceof MessagePort);
value.hereIsYourPort.postMessage('the worker is sending this');
value.hereIsYourPort.close();
});
}
'use strict';
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:
URL 时,数据会使用 ECMAScript 模块加载器根据 MIME 类型进行解释。如果options.eval
为true
,则这是一个包含 JavaScript 代码的字符串,而不是一个路径。options
<Object>argv
<any[]> 参数列表,这些参数将被字符串化并附加到工作线程中的process.argv
。这在很大程度上类似于workerData
,但这些值在全局process.argv
上可用,就好像它们是作为命令行选项传递给脚本一样。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
,则 Worker 会跟踪通过fs.open()
和fs.close()
管理的原始文件描述符,并在 Worker 退出时关闭它们,类似于网络套接字或通过FileHandle
API 管理的文件描述符等其他资源。此选项会自动被所有嵌套的Worker
继承。默认值:true
。transferList
<Object[]> 如果在workerData
中传递了一个或多个类MessagePort
的对象,则需要为这些项目提供一个transferList
,否则会抛出ERR_MISSING_MESSAGE_PORT_IN_TRANSFER_LIST
错误。更多信息请参见port.postMessage()
。resourceLimits
<Object> 新 JS 引擎实例的可选资源限制集。达到这些限制会导致Worker
实例的终止。这些限制只影响 JS 引擎,不影响包括ArrayBuffer
s 在内的任何外部数据。即使设置了这些限制,如果进程遇到全局内存不足的情况,仍可能中止。maxOldGenerationSizeMb
<number> 主堆的最大大小(MB)。如果设置了命令行参数--max-old-space-size
,它将覆盖此设置。maxYoungGenerationSizeMb
<number> 用于最近创建对象的堆空间的最大大小。如果设置了命令行参数--max-semi-space-size
,它将覆盖此设置。codeRangeSizeMb
<number> 用于生成代码的预分配内存范围的大小。stackSizeMb
<number> 线程的默认最大堆栈大小。较小的值可能导致 Worker 实例不可用。默认值:4
。
name
<string> 一个可选的name
,用于替换线程名称和工作线程标题,以用于调试/识别目的,最终标题为[worker ${id}] ${name}
。此参数有最大允许大小,具体取决于操作系统。如果提供的名称超出限制,它将被截断。- 最大大小
- Windows:32,767 个字符
- macOS:64 个字符
- Linux:16 个字符
- NetBSD:受限于
PTHREAD_MAX_NAMELEN_NP
- FreeBSD 和 OpenBSD:受限于
MAXCOMLEN
默认值:'WorkerThread'
。
- 最大大小
事件:'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'
事件之前发出。
事件:'online'
#
当工作线程开始执行 JavaScript 代码时,会发出 'online'
事件。
worker.cpuUsage([prev])
#
- 返回:<Promise>
此方法返回一个 Promise
,它将解析为一个与 process.threadCpuUsage()
相同的对象,或者如果工作线程不再运行,则以 ERR_WORKER_NOT_RUNNING
错误拒绝。此方法允许从实际线程外部观察统计信息。
worker.getHeapSnapshot([options])
#
返回一个可读流,用于获取工作线程当前状态的 V8 快照。更多详情请参阅 v8.getHeapSnapshot()
。
如果工作线程不再运行,这可能在发出 'exit'
事件之前发生,返回的 Promise
将立即以 ERR_WORKER_NOT_RUNNING
错误拒绝。
worker.getHeapStatistics()
#
- 返回:<Promise>
此方法返回一个 Promise
,它将解析为一个与 v8.getHeapStatistics()
相同的对象,或者如果工作线程不再运行,则以 ERR_WORKER_NOT_RUNNING
错误拒绝。此方法允许从实际线程外部观察统计信息。
worker.performance
#
一个可用于从工作线程实例查询性能信息的对象。类似于 perf_hooks.performance
。
performance.eventLoopUtilization([utilization1[, utilization2]])
#
utilization1
<Object> 上一次调用eventLoopUtilization()
的结果。utilization2
<Object> 在utilization1
之前上一次调用eventLoopUtilization()
的结果。- 返回:<Object>
与 perf_hooks
eventLoopUtilization()
的调用相同,只是返回的是工作线程实例的值。
一个区别是,与主线程不同,工作线程内的引导是在事件循环内完成的。因此,一旦工作线程的脚本开始执行,事件循环利用率就立即可用。
一个不增加的 idle
时间并不表示工作线程卡在引导阶段。以下示例显示了工作线程的整个生命周期从未累积任何 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('msg')).unref();
(function r(n) {
if (--n < 0) return;
const t = Date.now();
while (Date.now() - t < 300);
setImmediate(r, n);
})(10);
}
'use strict';
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();
} else {
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);
}
工作线程的事件循环利用率仅在发出 'online'
事件后可用,如果在此之前或在 'exit'
事件之后调用,则所有属性的值都为 0
。
worker.postMessage(value[, transferList])
#
value
<any>transferList
<Object[]>
向工作线程发送一条消息,该消息通过 require('node:worker_threads').parentPort.on('message')
接收。更多详情请参阅 port.postMessage()
。
worker.ref()
#
与 unref()
相反,在一个先前被 unref()
的工作线程上调用 ref()
并*不*让程序在它是唯一活动句柄的情况下退出(默认行为)。如果工作线程已经被 ref()
,再次调用 ref()
没有效果。
worker.resourceLimits
#
- 类型:<Object>
提供此工作线程的 JS 引擎资源约束集。如果 resourceLimits
选项已传递给 Worker
构造函数,则此值与其值匹配。
如果工作线程已停止,则返回值为一个空对象。
worker.startCpuProfile()
#
- 返回:<Promise>
启动 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();
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('node:worker_threads');
parentPort.on('message', () => {});
`, { eval: true });
w.on('online', async () => {
// Stop profile automatically when return and profile will be discarded
await using handle = await w.startCpuProfile();
});
worker.startHeapProfile()
#
- 返回:<Promise>
启动堆分析,然后返回一个 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('node:worker_threads');
parentPort.on('message', () => {});
`, { eval: true });
w.on('online', async () => {
// Stop profile automatically when return and profile will be discarded
await using handle = await w.startHeapProfile();
});
worker.stderr
#
这是一个可读流,其中包含写入工作线程内部 process.stderr
的数据。如果没有将 stderr: true
传递给 Worker
构造函数,那么数据将被管道传输到父线程的 process.stderr
流。
worker.stdin
#
- 类型:<null> | <stream.Writable>
如果将 stdin: true
传递给了 Worker
构造函数,那么这是一个可写流。写入此流的数据将在工作线程中作为 process.stdin
可用。
worker.stdout
#
这是一个可读流,其中包含写入工作线程内部 process.stdout
的数据。如果没有将 stdout: true
传递给 Worker
构造函数,那么数据将被管道传输到父线程的 process.stdout
流。
worker.terminate()
#
- 返回:<Promise>
尽快停止工作线程中的所有 JavaScript 执行。返回一个 Promise,该 Promise 在 'exit'
事件发出时兑现退出码。
worker.threadId
#
- 类型:<integer>
所引用线程的整数标识符。在工作线程内部,它作为 require('node:worker_threads').threadId
可用。此值对于单个进程内的每个 Worker
实例都是唯一的。
worker.threadName
#
所引用线程的字符串标识符,如果线程未运行则为 null。在工作线程内部,它作为 require('node:worker_threads').threadName
可用。
worker.unref()
#
在一个工作线程上调用 unref()
允许线程在它是事件系统中唯一活动句柄时退出。如果工作线程已经被 unref()
,再次调用 unref()
没有效果。
worker[Symbol.asyncDispose]()
#
当 dispose 作用域退出时,调用 worker.terminate()
。
async function example() {
await using worker = new Worker('for (;;) {}', { eval: true });
// Worker is automatically terminate when the scope is exited.
}
注意#
stdio 的同步阻塞#
Worker
利用通过 <MessagePort> 的消息传递来实现与 stdio
的交互。这意味着源自 Worker
的 stdio
输出可能会被接收端的同步代码阻塞,该代码阻塞了 Node.js 事件循环。
import {
Worker,
isMainThread,
} from 'node: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
选项,否则新的工作线程会自动继承正在运行的进程的命令行标志,并将预加载与主线程相同的预加载脚本。如果预加载脚本无条件地启动一个工作线程,那么每个派生的线程都会派生另一个线程,直到应用程序崩溃。