Node.js v21.7.2 文件
- Node.js v21.7.2
-
► 目錄
- 工作執行緒
worker.getEnvironmentData(key)
worker.isMainThread
worker.markAsUntransferable(object)
worker.isMarkedAsUntransferable(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
- 注意事項
- 工作執行緒
-
► 索引
- 斷言測試
- 非同步內容追蹤
- 非同步掛鉤
- 緩衝區
- C++ 外掛程式
- 使用 Node-API 的 C/C++ 外掛程式
- C++ 嵌入式 API
- 子程序
- 叢集
- 命令列選項
- 主控台
- Corepack
- 加密
- 偵錯器
- 已棄用的 API
- 診斷頻道
- DNS
- 網域
- 錯誤
- 事件
- 檔案系統
- 全域變數
- HTTP
- HTTP/2
- HTTPS
- 檢查器
- 國際化
- 模組:CommonJS 模組
- 模組:ECMAScript 模組
- 模組:
node:module
API - 模組:套件
- 網路
- 作業系統
- 路徑
- 效能掛鉤
- 權限
- 程序
- Punycode
- 查詢字串
- 讀取命令列
- REPL
- 報告
- 單一可執行應用程式
- 串流
- 字串解碼器
- 測試執行器
- 計時器
- TLS/SSL
- 追蹤事件
- TTY
- UDP/資料包
- URL
- 公用程式
- V8
- VM
- WASI
- Web Crypto API
- Web Streams API
- 工作執行緒
- Zlib
- ► 其他版本
- ► 選項
工作執行緒#
node:worker_threads
模組可使用平行執行 JavaScript 的執行緒。若要存取它
const worker = require('node:worker_threads');
執行緒(工作執行緒)可用於執行密集運算的 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
文件中的 "使用 AsyncResource
作為 Worker
執行緒池" 以取得範例實作。
工作執行緒預設會繼承非程序特定的選項。請參閱 Worker 建構函式選項
以了解如何自訂工作執行緒選項,特別是 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
<any> 任何可任意指定的 JavaScript 值。
將物件標記為不可傳輸。如果 object
出現在 port.postMessage()
呼叫的傳輸清單中,則會擲回錯誤。如果 object
是基本值,則這是一個空操作。
特別是,對於可以複製(而非傳輸)且由傳送端上的其他物件使用的物件而言,這很有意義。例如,Node.js 會使用此標記其用於 Buffer
池 的 ArrayBuffer
。
此操作無法復原。
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.isMarkedAsUntransferable(object)
#
檢查物件是否已標示為不可轉移,方法為 markAsUntransferable()
。
const { markAsUntransferable, isMarkedAsUntransferable } = require('node:worker_threads');
const pooledBuffer = new ArrayBuffer(8);
markAsUntransferable(pooledBuffer);
isMarkedAsUntransferable(pooledBuffer); // Returns true.
瀏覽器中沒有等效的 API。
worker.moveMessagePortToContext(port, contextifiedSandbox)
#
-
port
<MessagePort> 要轉移的訊息埠。 -
contextifiedSandbox
<Object> 由vm.createContext()
方法傳回的 context 化 物件。
將 MessagePort
轉移到不同的 vm
Context。原始 port
物件將無法使用,而傳回的 MessagePort
執行個體將取代其位置。
傳回的 MessagePort
是目標 context 中的物件,並繼承其全域 Object
類別。傳遞至 port.onmessage()
偵聽器的物件也會在目標 context 中建立,並繼承其全域 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> 任何可任意指定的、可複製的 JavaScript 值,可用作 <Map> 鍵。value
<任何> 任何可複製的任意 JavaScript 值,將複製並自動傳遞給所有新的Worker
執行個體。如果value
傳遞為undefined
,則key
的任何先前設定值都將被刪除。
worker.setEnvironmentData()
API 設定目前執行緒和從目前內容產生所有新 Worker
執行個體中 worker.getEnvironmentData()
的內容。
worker.threadId
#
目前執行緒的整數識別碼。在對應的工作物件(如果有)中,它可用作 worker.threadId
。此值在單一程序內對每個 Worker
執行個體都是唯一的。
worker.workerData
#
一個包含傳遞給此執行緒的 Worker
建構函式的資料的複製之任意 JavaScript 值。
資料會像使用 postMessage()
一樣複製,根據 HTML 結構化複製演算法。
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()
的 BroadcastChannel 呼叫 ref()
不會 讓程式在它是唯一剩餘的活動控制項時結束(預設行為)。如果埠是 ref()
,再次呼叫 ref()
沒有作用。
broadcastChannel.unref()
#
對 BroadcastChannel 呼叫 unref()
允許執行緒在事件系統中這是唯一活動的控制項時結束。如果 BroadcastChannel 已 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
#
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 物件時發生錯誤時,就會發出此事件。這種情況很少見,但可能會發生,例如,當在 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
、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
中)。與 子程序 不同,目前不支援傳輸網路 socket 等處理程序。
如果 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 和 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
,否則不得傳輸 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.hasRef()
#
- 傳回:<boolean>
如果為 true,MessagePort
物件將保持 Node.js 事件迴圈處於作用中。
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
#
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
傳遞給另一個執行緒。
請參閱 port.postMessage()
,以取得關於如何傳遞訊息,以及哪些 JavaScript 值可以成功傳輸過執行緒障礙的更多資訊。
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
<字串> | <URL> 工作執行緒主程式碼或模組的路徑。必須是絕對路徑或從./
或../
開始的相對路徑(即相對於目前工作目錄),或使用file:
或data:
協定的 WHATWGURL
物件。使用data:
URL 時,資料會根據 MIME 類型使用 ECMAScript 模組載入器 進行詮釋。如果options.eval
為true
,則這是一個包含 JavaScript 程式碼的字串,而非路徑。options
<物件>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[]> 傳遞至工作執行緒的節點 CLI 選項清單。V8 選項(例如--max-old-space-size
)和影響程序的選項(例如--title
)不受支援。如果設定,則在工作執行緒內提供為process.execArgv
。預設情況下,選項會從父執行緒繼承。stdin
<布林值> 如果將此設定為true
,則worker.stdin
會提供一個可寫入串流,其內容會顯示在 Worker 內的process.stdin
中。預設情況下,不會提供任何資料。stdout
<布林值> 如果將此設定為true
,則worker.stdout
就不會自動透過父代中的process.stdout
傳遞。stderr
<布林值> 如果將此設定為true
,則worker.stderr
就不會自動透過父代中的process.stderr
傳遞。workerData
<任何> 任何 JavaScript 值,會被複製並作為require('node:worker_threads').workerData
提供。複製會依據 HTML 結構化複製演算法 中所述進行,如果無法複製物件(例如因為它包含function
),就會擲回錯誤。trackUnmanagedFds
<布林值> 如果將此設定為true
,則 Worker 會追蹤透過fs.open()
和fs.close()
管理的原始檔案描述符,並在 Worker 退出時關閉它們,類似於透過FileHandle
API 管理的其他資源,例如網路 socket 或檔案描述符。此選項會自動繼承至所有巢狀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> 執行緒的預設最大堆疊大小。較小的值可能會導致無法使用的 Worker 執行個體。預設:4
。
name
<string> 選用的name
,會附加到 worker 標題中以進行偵錯/識別,使最終標題為[worker ${id}] ${name}
。預設:''
。
事件:'error'
#
err
<Error>
如果 worker 執行緒擲回未捕捉的例外狀況,就會發出 'error'
事件。在這種情況下,worker 會終止。
事件:'exit'
#
exitCode
<整數>
當工作執行緒停止後,會發出 '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([options])
#
傳回工作執行緒目前狀態的 V8 快照的可讀取串流。請參閱 v8.getHeapSnapshot()
以取得更多詳細資料。
如果工作執行緒不再執行,這可能會在發出 'exit'
事件 之前發生,則傳回的 Promise
會立即以 ERR_WORKER_NOT_RUNNING
錯誤拒絕。
worker.performance
#
一個物件,可用於查詢工作執行緒執行個體的效能資訊。類似於 perf_hooks.performance
。
performance.eventLoopUtilization([utilization1[, utilization2]])
#
utilization1
<Object> 先前呼叫eventLoopUtilization()
的結果。utilization2
<Object> 先前呼叫eventLoopUtilization()
在utilization1
之前的結果。- 傳回:<Object>
與 perf_hooks
eventLoopUtilization()
相同的呼叫,但會傳回工作執行緒執行個體的值。
一個不同點是,與主執行緒不同,工作執行緒中的開機作業是在事件迴圈中完成的。因此,事件迴圈使用率在工作執行緒的腳本開始執行後便會立即提供。
未增加的 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);
工作執行緒的事件迴圈使用率僅在發出 '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
#
提供此工作執行緒執行緒的 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 執行。傳回 Promise 以取得在發出 'exit'
事件 時完成的結束代碼。
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
選項,否則新的工作執行緒會自動繼承執行中程序的命令列旗標,而且會預載與主執行緒相同的預載指令碼。如果預載指令碼無條件啟動工作執行緒,每個衍生的執行緒都會衍生另一個執行緒,直到應用程式崩潰為止。