工作執行緒#

穩定性:2 - 穩定

原始碼: lib/worker_threads.js

node:worker_threads 模組可使用平行執行 JavaScript 的執行緒。若要存取它

const worker = require('node:worker_threads'); 

執行緒(工作執行緒)可用於執行密集運算的 JavaScript 作業。它們對密集 I/O 作業的幫助不大。Node.js 內建非同步 I/O 作業比工作執行緒更有效率。

child_processcluster 不同,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 建構函式選項 以了解如何自訂工作執行緒選項,特別是 argvexecArgv 選項。

worker.getEnvironmentData(key)#

  • key <any> 任何可任意指定的、可複製的 JavaScript 值,可用作 <Map> 鍵。
  • 傳回:<any>

在工作執行緒中,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 會使用此標記其用於 BufferArrayBuffer

此操作無法復原。

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)#

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)#

從給定的 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() 產生一個物件,具有 port1port2 屬性,它們參照連結的 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'#

當訊息解序失敗時,會發出 'messageerror' 事件。

目前,當在接收端建立已發佈的 JS 物件時發生錯誤時,就會發出此事件。這種情況很少見,但可能會發生,例如,當在 vm.Context(目前 Node.js API 不可用的地方)中收到某些 Node.js API 物件時。

port.close()#

停用連線任一端的進一步訊息傳送。當不再透過此 MessagePort 進行進一步通訊時,可以呼叫此方法。

屬於通道一部分的兩個 MessagePort 執行個體上都會發出 'close' 事件

port.postMessage(value[, transferList])#

將 JavaScript 值傳送至該通道的接收方。value 的傳輸方式與 HTML 結構化複製演算法 相容。

特別是,與 JSON 有顯著差異的地方:

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 可能是一個 ArrayBufferMessagePortFileHandle 物件的清單。傳輸後,它們將無法再在頻道的傳送端使用(即使它們未包含在 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 時的注意事項#

所有 TypedArrayBuffer 執行個體都是基礎 ArrayBuffer 的檢視。也就是說,實際儲存原始資料的是 ArrayBuffer,而 TypedArrayBuffer 物件提供檢視和處理資料的方法。建立多個檢視在同一個 ArrayBuffer 執行個體上是可能且常見的。使用傳輸清單傳輸 ArrayBuffer 時必須非常小心,因為這樣做會導致所有共用同一個 ArrayBufferTypedArrayBuffer 執行個體都無法使用。

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()#

穩定性:1 - 實驗性

如果為 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 環境中的顯著差異是

可以在其他 Worker 內建立 Worker 實例。

Web Workersnode: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: 協定的 WHATWG URL 物件。使用 data: URL 時,資料會根據 MIME 類型使用 ECMAScript 模組載入器 進行詮釋。如果 options.evaltrue,則這是一個包含 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'#

如果 worker 執行緒擲回未捕捉的例外狀況,就會發出 'error' 事件。在這種情況下,worker 會終止。

事件:'exit'#

當工作執行緒停止後,會發出 'exit' 事件。如果工作執行緒透過呼叫 process.exit() 來結束,則 exitCode 參數會傳遞結束代碼。如果工作執行緒遭到終止,則 exitCode 參數會是 1

這是任何 Worker 實例發出的最後一個事件。

事件:'message'#

  • value <any> 傳輸的值

當工作執行緒呼叫 require('node:worker_threads').parentPort.postMessage() 時,會發出 'message' 事件。請參閱 port.on('message') 事件以取得更多詳細資料。

Worker 物件上發出 'exit' 事件 之前,會發出從工作執行緒傳送的所有訊息。

事件:'messageerror'#

當訊息解序失敗時,會發出 'messageerror' 事件。

事件:'online'#

當工作執行緒開始執行 JavaScript 程式碼時,會發出 'online' 事件。

worker.getHeapSnapshot([options])#

  • options <物件>
    • exposeInternals <布林值> 如果為 true,則在堆快照中公開內部結構。預設值: false
    • exposeNumericValues <布林值> 如果為 true,則在人工欄位中公開數值。預設值: false
  • 傳回:<Promise> 包含 V8 堆快照的可讀取串流的 Promise

傳回工作執行緒目前狀態的 V8 快照的可讀取串流。請參閱 v8.getHeapSnapshot() 以取得更多詳細資料。

如果工作執行緒不再執行,這可能會在發出 'exit' 事件 之前發生,則傳回的 Promise 會立即以 ERR_WORKER_NOT_RUNNING 錯誤拒絕。

worker.performance#

一個物件,可用於查詢工作執行緒執行個體的效能資訊。類似於 perf_hooks.performance

performance.eventLoopUtilization([utilization1[, utilization2]])#

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])#

透過 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()#

盡快停止工作執行緒中的所有 JavaScript 執行。傳回 Promise 以取得在發出 'exit' 事件 時完成的結束代碼。

worker.threadId#

參考執行緒的整數識別碼。在工作執行緒內,它可用作 require('node:worker_threads').threadId。此值在單一程序內的每個 Worker 執行個體都是唯一的。

worker.unref()#

在工作執行緒上呼叫 unref() 可讓執行緒在事件系統中這是唯一活動的控制代碼時退出。如果工作執行緒已經 unref(),再次呼叫 unref() 沒有作用。

備註#

stdio 的同步封鎖#

Worker 使用透過 <MessagePort> 傳遞訊息的方式來實作與 stdio 的互動。這表示來自 Workerstdio 輸出可能會被接收端同步程式碼封鎖,而該程式碼封鎖了 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 選項,否則新的工作執行緒會自動繼承執行中程序的命令列旗標,而且會預載與主執行緒相同的預載指令碼。如果預載指令碼無條件啟動工作執行緒,每個衍生的執行緒都會衍生另一個執行緒,直到應用程式崩潰為止。