Skip to content

Worker-Threads

[Stabil: 2 - Stabil]

Stabil: 2 Stabilität: 2 - Stabil

Quellcode: lib/worker_threads.js

Das Modul node:worker_threads ermöglicht die Verwendung von Threads, die JavaScript parallel ausführen. Um darauf zuzugreifen:

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

Worker (Threads) sind nützlich, um CPU-intensive JavaScript-Operationen durchzuführen. Bei E/A-intensiven Arbeiten helfen sie nicht viel. Die in Node.js eingebauten asynchronen E/A-Operationen sind effizienter als Worker es sein können.

Im Gegensatz zu child_process oder cluster können worker_threads Speicher gemeinsam nutzen. Sie tun dies, indem sie ArrayBuffer-Instanzen übertragen oder SharedArrayBuffer-Instanzen gemeinsam nutzen.

js
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 wurde mit Exit-Code ${code} gestoppt`))
      })
    })
  }
} else {
  const { parse } = require('some-js-parsing-library')
  const script = workerData
  parentPort.postMessage(parse(script))
}

Das obige Beispiel erzeugt einen Worker-Thread für jeden parseJSAsync()-Aufruf. In der Praxis sollte für diese Art von Aufgaben ein Pool von Workern verwendet werden. Andernfalls würde der Overhead beim Erstellen von Workern wahrscheinlich ihren Nutzen übersteigen.

Verwenden Sie bei der Implementierung eines Worker-Pools die AsyncResource-API, um Diagnosetools (z. B. zur Bereitstellung asynchroner Stack-Traces) über die Korrelation zwischen Aufgaben und deren Ergebnissen zu informieren. Ein Beispiel für eine Implementierung finden Sie unter "Verwenden von AsyncResource für einen Worker-Threadpool" in der async_hooks-Dokumentation.

Worker-Threads erben standardmäßig nicht-prozessspezifische Optionen. Informationen zur Anpassung von Worker-Thread-Optionen, insbesondere der argv- und execArgv-Optionen, finden Sie unter Worker-Konstruktoroptionen.

worker.getEnvironmentData(key)

[Verlauf]

VersionÄnderungen
v17.5.0, v16.15.0Nicht mehr experimentell.
v15.12.0, v14.18.0Hinzugefügt in: v15.12.0, v14.18.0
  • key <any> Ein beliebiger, klonbarer JavaScript-Wert, der als <Map>-Schlüssel verwendet werden kann.
  • Gibt zurück: <any>

Innerhalb eines Worker-Threads gibt worker.getEnvironmentData() einen Klon der Daten zurück, die dem erzeugenden Thread über worker.setEnvironmentData() übergeben wurden. Jeder neue Worker erhält automatisch seine eigene Kopie der Umgebungsdaten.

js
const { Worker, isMainThread, setEnvironmentData, getEnvironmentData } = require('node:worker_threads')

if (isMainThread) {
  setEnvironmentData('Hallo', 'Welt!')
  const worker = new Worker(__filename)
} else {
  console.log(getEnvironmentData('Hallo')) // Gibt 'Welt!' aus.
}

worker.isMainThread

Hinzugefügt in: v10.5.0

Ist true, wenn dieser Code nicht innerhalb eines Worker-Threads ausgeführt wird.

js
const { Worker, isMainThread } = require('node:worker_threads')

if (isMainThread) {
  // Lädt die aktuelle Datei in einer Worker-Instanz neu.
  new Worker(__filename)
} else {
  console.log('Im Worker!')
  console.log(isMainThread) // Gibt 'false' aus.
}

worker.markAsUntransferable(object)

Hinzugefügt in: v14.5.0, v12.19.0

  • object <any> Ein beliebiger JavaScript-Wert.

Markiert ein Objekt als nicht übertragbar. Wenn object in der Übertragungsliste eines port.postMessage()-Aufrufs vorkommt, wird ein Fehler ausgelöst. Dies ist ein No-Op, wenn object ein primitiver Wert ist.

Dies ist insbesondere sinnvoll für Objekte, die geklont und nicht übertragen werden können und die von anderen Objekten auf der sendenden Seite verwendet werden. Node.js markiert beispielsweise die ArrayBuffers, die es für seinen Buffer-Pool verwendet, damit.

Diese Operation kann nicht rückgängig gemacht werden.

js
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 {
  // Dies löst einen Fehler aus, da pooledBuffer nicht übertragbar ist.
  port1.postMessage(typedArray1, [typedArray1.buffer])
} catch (error) {
  // error.name === 'DataCloneError'
}

// Die folgende Zeile gibt den Inhalt von typedArray1 aus -- er besitzt immer noch
// seinen Speicher und wurde nicht übertragen. Ohne
// `markAsUntransferable()` würde dies ein leeres Uint8Array ausgeben und der
// postMessage-Aufruf wäre erfolgreich gewesen.
// typedArray2 ist ebenfalls intakt.
console.log(typedArray1)
console.log(typedArray2)

Es gibt kein Äquivalent zu dieser API in Browsern.

worker.isMarkedAsUntransferable(object)

Hinzugefügt in: v21.0.0

Prüft, ob ein Objekt mit markAsUntransferable() als nicht übertragbar markiert wurde.

js
const { markAsUntransferable, isMarkedAsUntransferable } = require('node:worker_threads')

const pooledBuffer = new ArrayBuffer(8)
markAsUntransferable(pooledBuffer)

isMarkedAsUntransferable(pooledBuffer) // Gibt true zurück.

Es gibt keine Entsprechung zu dieser API in Browsern.

worker.markAsUncloneable(object)

Hinzugefügt in: v23.0.0

  • object <any> Beliebiger JavaScript-Wert.

Markiert ein Objekt als nicht klonbar. Wenn object als message in einem port.postMessage() Aufruf verwendet wird, wird ein Fehler ausgelöst. Dies ist ein No-Op, wenn object ein primitiver Wert ist.

Dies hat keine Auswirkungen auf ArrayBuffer oder ähnliche Buffer-Objekte.

Diese Operation kann nicht rückgängig gemacht werden.

js
const { markAsUncloneable } = require('node:worker_threads')

const anyObject = { foo: 'bar' }
markAsUncloneable(anyObject)
const { port1 } = new MessageChannel()
try {
  // Dies wird einen Fehler auslösen, da anyObject nicht klonbar ist.
  port1.postMessage(anyObject)
} catch (error) {
  // error.name === 'DataCloneError'
}

Es gibt keine Entsprechung zu dieser API in Browsern.

worker.moveMessagePortToContext(port, contextifiedSandbox)

Hinzugefügt in: v11.13.0

Überträgt einen MessagePort in einen anderen vm Kontext. Das ursprüngliche port-Objekt wird unbrauchbar gemacht, und die zurückgegebene MessagePort-Instanz übernimmt dessen Platz.

Der zurückgegebene MessagePort ist ein Objekt im Zielkontext und erbt von seiner globalen Object-Klasse. Objekte, die an den port.onmessage() Listener übergeben werden, werden ebenfalls im Zielkontext erstellt und erben von seiner globalen Object-Klasse.

Der erstellte MessagePort erbt jedoch nicht mehr von EventTarget, und nur port.onmessage() kann verwendet werden, um Ereignisse damit zu empfangen.

worker.parentPort

Hinzugefügt in: v10.5.0

Wenn dieser Thread ein Worker ist, ist dies ein MessagePort, der die Kommunikation mit dem übergeordneten Thread ermöglicht. Nachrichten, die mit parentPort.postMessage() gesendet werden, sind im übergeordneten Thread mit worker.on('message') verfügbar, und Nachrichten, die vom übergeordneten Thread mit worker.postMessage() gesendet werden, sind in diesem Thread mit parentPort.on('message') verfügbar.

js
const { Worker, isMainThread, parentPort } = require('node:worker_threads')

if (isMainThread) {
  const worker = new Worker(__filename)
  worker.once('message', message => {
    console.log(message) // Gibt 'Hello, world!' aus.
  })
  worker.postMessage('Hello, world!')
} else {
  // Wenn eine Nachricht vom übergeordneten Thread empfangen wird, senden Sie sie zurück:
  parentPort.once('message', message => {
    parentPort.postMessage(message)
  })
}

worker.postMessageToThread(threadId, value[, transferList][, timeout])

Hinzugefügt in: v22.5.0

[Stabil: 1 - Experimentell]

Stabil: 1 Stabilität: 1.1 - Aktive Entwicklung

  • threadId <number> Die Ziel-Thread-ID. Wenn die Thread-ID ungültig ist, wird ein ERR_WORKER_MESSAGING_FAILED-Fehler ausgelöst. Wenn die Ziel-Thread-ID die aktuelle Thread-ID ist, wird ein ERR_WORKER_MESSAGING_SAME_THREAD-Fehler ausgelöst.
  • value <any> Der zu sendende Wert.
  • transferList <Object[]> Wenn ein oder mehrere MessagePort-ähnliche Objekte in value übergeben werden, ist eine transferList für diese Elemente erforderlich oder ERR_MISSING_MESSAGE_PORT_IN_TRANSFER_LIST wird ausgelöst. Siehe port.postMessage() für weitere Informationen.
  • timeout <number> Zeit, die in Millisekunden auf die Zustellung der Nachricht gewartet wird. Standardmäßig ist es undefined, was bedeutet, dass unbegrenzt gewartet wird. Wenn die Operation zeitlich überschritten wird, wird ein ERR_WORKER_MESSAGING_TIMEOUT-Fehler ausgelöst.
  • Gibt zurück: <Promise> Ein Promise, das erfüllt wird, wenn die Nachricht vom Ziel-Thread erfolgreich verarbeitet wurde.

Sendet einen Wert an einen anderen Worker, der durch seine Thread-ID identifiziert wird.

Wenn der Ziel-Thread keinen Listener für das workerMessage-Ereignis hat, löst die Operation einen ERR_WORKER_MESSAGING_FAILED-Fehler aus.

Wenn der Ziel-Thread während der Verarbeitung des workerMessage-Ereignisses einen Fehler ausgelöst hat, löst die Operation einen ERR_WORKER_MESSAGING_ERRORED-Fehler aus.

Diese Methode sollte verwendet werden, wenn der Ziel-Thread nicht der direkte übergeordnete oder untergeordnete Thread des aktuellen Threads ist. Wenn die beiden Threads über- und untergeordnet sind, verwenden Sie require('node:worker_threads').parentPort.postMessage() und worker.postMessage(), um die Threads kommunizieren zu lassen.

Das folgende Beispiel zeigt die Verwendung von postMessageToThread: Es erstellt 10 verschachtelte Threads, der letzte wird versuchen, mit dem Hauptthread zu kommunizieren.

js
import { fileURLToPath } from 'node:url'
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(fileURLToPath(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
js
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.receiveMessageOnPort(port)

[Verlauf]

VersionÄnderungen
v15.12.0Das Port-Argument kann nun auch auf einen BroadcastChannel verweisen.
v12.3.0Hinzugefügt in: v12.3.0

Empfängt eine einzelne Nachricht von einem gegebenen MessagePort. Wenn keine Nachricht verfügbar ist, wird undefined zurückgegeben, andernfalls ein Objekt mit einer einzelnen message-Eigenschaft, die die Nutzlast der Nachricht enthält, entsprechend der ältesten Nachricht in der Warteschlange des MessagePort.

js
const { MessageChannel, receiveMessageOnPort } = require('node:worker_threads')
const { port1, port2 } = new MessageChannel()
port1.postMessage({ hello: 'world' })

console.log(receiveMessageOnPort(port2))
// Gibt aus: { message: { hello: 'world' } }
console.log(receiveMessageOnPort(port2))
// Gibt aus: undefined

Wenn diese Funktion verwendet wird, wird kein 'message'-Ereignis ausgelöst und der onmessage-Listener wird nicht aufgerufen.

worker.resourceLimits

Hinzugefügt in: v13.2.0, v12.16.0

Stellt den Satz von Ressourcenbeschränkungen der JS-Engine innerhalb dieses Worker-Threads bereit. Wenn die Option resourceLimits an den Worker-Konstruktor übergeben wurde, entspricht dies seinen Werten.

Wenn dies im Hauptthread verwendet wird, ist sein Wert ein leeres Objekt.

worker.SHARE_ENV

Hinzugefügt in: v11.14.0

Ein spezieller Wert, der als env-Option des Worker-Konstruktors übergeben werden kann, um anzugeben, dass der aktuelle Thread und der Worker-Thread gemeinsam Lese- und Schreibzugriff auf denselben Satz von Umgebungsvariablen haben sollen.

js
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) // Gibt 'foo' aus.
})

worker.setEnvironmentData(key[, value])

[Verlauf]

VersionÄnderungen
v17.5.0, v16.15.0Nicht mehr experimentell.
v15.12.0, v14.18.0Hinzugefügt in: v15.12.0, v14.18.0
  • key <any> Ein beliebiger, klonbarer JavaScript-Wert, der als <Map>-Schlüssel verwendet werden kann.
  • value <any> Ein beliebiger, klonbarer JavaScript-Wert, der geklont und automatisch an alle neuen Worker-Instanzen übergeben wird. Wenn value als undefined übergeben wird, wird jeder zuvor für den key gesetzte Wert gelöscht.

Die worker.setEnvironmentData()-API setzt den Inhalt von worker.getEnvironmentData() im aktuellen Thread und allen neuen Worker-Instanzen, die aus dem aktuellen Kontext erzeugt werden.

worker.threadId

Hinzugefügt in: v10.5.0

Eine ganzzahlige Kennung für den aktuellen Thread. Auf dem entsprechenden Worker-Objekt (falls vorhanden) ist sie als worker.threadId verfügbar. Dieser Wert ist für jede Worker-Instanz innerhalb eines einzigen Prozesses eindeutig.

worker.workerData

Hinzugefügt in: v10.5.0

Ein beliebiger JavaScript-Wert, der eine Kopie der Daten enthält, die dem Konstruktor Worker dieses Threads übergeben wurden.

Die Daten werden so geklont, als ob sie mit postMessage() gemäß dem HTML-Struktur-Klon-Algorithmus geklont würden.

js
const { Worker, isMainThread, workerData } = require('node:worker_threads')

if (isMainThread) {
  const worker = new Worker(__filename, { workerData: 'Hallo, Welt!' })
} else {
  console.log(workerData) // Gibt 'Hallo, Welt!' aus.
}

Klasse: BroadcastChannel extends EventTarget

[Verlauf]

VersionÄnderungen
v18.0.0Nicht mehr experimentell.
v15.4.0Hinzugefügt in: v15.4.0

Instanzen von BroadcastChannel ermöglichen eine asynchrone Eins-zu-Viele-Kommunikation mit allen anderen BroadcastChannel-Instanzen, die an denselben Kanalnamen gebunden sind.

js
'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('Hallo von jedem Worker')
  bc.close()
}

new BroadcastChannel(name)

Hinzugefügt in: v15.4.0

  • name <beliebig> Der Name des Kanals, mit dem eine Verbindung hergestellt werden soll. Jeder JavaScript-Wert, der mit ${name} in einen String konvertiert werden kann, ist zulässig.

broadcastChannel.close()

Hinzugefügt in: v15.4.0

Schließt die BroadcastChannel-Verbindung.

broadcastChannel.onmessage

Hinzugefügt in: v15.4.0

  • Typ: <Funktion> Wird mit einem einzelnen MessageEvent-Argument aufgerufen, wenn eine Nachricht empfangen wird.

broadcastChannel.onmessageerror

Hinzugefügt in: v15.4.0

  • Typ: <Funktion> Wird aufgerufen, wenn eine empfangene Nachricht nicht deserialisiert werden kann.

broadcastChannel.postMessage(message)

Hinzugefügt in: v15.4.0

  • message <any> Jeder klonbare JavaScript-Wert.

broadcastChannel.ref()

Hinzugefügt in: v15.4.0

Das Gegenteil von unref(). Das Aufrufen von ref() auf einem zuvor unref()ed BroadcastChannel bewirkt nicht, dass das Programm beendet wird, wenn es der einzige aktive Handle ist (das Standardverhalten). Wenn der Port ref()ed ist, hat ein erneutes Aufrufen von ref() keine Auswirkung.

broadcastChannel.unref()

Hinzugefügt in: v15.4.0

Das Aufrufen von unref() auf einem BroadcastChannel ermöglicht es dem Thread, sich zu beenden, wenn dies der einzige aktive Handle im Ereignissystem ist. Wenn der BroadcastChannel bereits unref()ed ist, hat ein erneutes Aufrufen von unref() keine Auswirkung.

Klasse: MessageChannel

Hinzugefügt in: v10.5.0

Instanzen der worker.MessageChannel-Klasse stellen einen asynchronen Zwei-Wege-Kommunikationskanal dar. Die MessageChannel hat keine eigenen Methoden. new MessageChannel() erzeugt ein Objekt mit den Eigenschaften port1 und port2, die auf verknüpfte MessagePort-Instanzen verweisen.

js
const { MessageChannel } = require('node:worker_threads')

const { port1, port2 } = new MessageChannel()
port1.on('message', message => console.log('empfangen', message))
port2.postMessage({ foo: 'bar' })
// Gibt aus: empfangen { foo: 'bar' } vom `port1.on('message')`-Listener

Klasse: MessagePort

[Verlauf]

VersionÄnderungen
v14.7.0Diese Klasse erbt jetzt von EventTarget anstelle von EventEmitter.
v10.5.0Hinzugefügt in: v10.5.0

Instanzen der worker.MessagePort-Klasse stellen ein Ende eines asynchronen Zwei-Wege-Kommunikationskanals dar. Es kann verwendet werden, um strukturierte Daten, Speicherbereiche und andere MessagePorts zwischen verschiedenen Workers zu übertragen.

Diese Implementierung entspricht Browser MessagePorts.

Ereignis: 'close'

Hinzugefügt in: v10.5.0

Das Ereignis 'close' wird einmal ausgelöst, wenn eine Seite des Kanals getrennt wurde.

js
const { MessageChannel } = require('node:worker_threads')
const { port1, port2 } = new MessageChannel()

// Gibt Folgendes aus:
//   foobar
//   geschlossen!
port2.on('message', message => console.log(message))
port2.on('close', () => console.log('geschlossen!'))

port1.postMessage('foobar')
port1.close()

Ereignis: 'message'

Hinzugefügt in: v10.5.0

  • value <any> Der übertragene Wert

Das Ereignis 'message' wird für jede eingehende Nachricht ausgelöst und enthält den geklonten Eingabewert von port.postMessage().

Listener für dieses Ereignis empfangen einen Klon des value-Parameters, wie er an postMessage() übergeben wurde, und keine weiteren Argumente.

Ereignis: 'messageerror'

Hinzugefügt in: v14.5.0, v12.19.0

Das Ereignis 'messageerror' wird ausgelöst, wenn die Deserialisierung einer Nachricht fehlgeschlagen ist.

Derzeit wird dieses Ereignis ausgelöst, wenn beim Instanziieren des übermittelten JS-Objekts auf der Empfängerseite ein Fehler auftritt. Solche Situationen sind selten, können aber beispielsweise auftreten, wenn bestimmte Node.js-API-Objekte in einem vm.Context empfangen werden (wo Node.js-APIs derzeit nicht verfügbar sind).

port.close()

Hinzugefügt in: v10.5.0

Deaktiviert das weitere Senden von Nachrichten auf beiden Seiten der Verbindung. Diese Methode kann aufgerufen werden, wenn über diesen MessagePort keine weitere Kommunikation stattfindet.

Das 'close'-Ereignis wird auf beiden MessagePort-Instanzen ausgelöst, die Teil des Kanals sind.

port.postMessage(value[, transferList])

[Verlauf]

VersionÄnderungen
v21.0.0Es wird ein Fehler ausgelöst, wenn sich ein nicht übertragbares Objekt in der Übertragungsliste befindet.
v15.6.0X509Certificate wurde der Liste der klonbaren Typen hinzugefügt.
v15.0.0CryptoKey wurde der Liste der klonbaren Typen hinzugefügt.
v15.14.0, v14.18.0'BlockList' zur Liste der klonbaren Typen hinzugefügt.
v15.9.0, v14.18.0'Histogram'-Typen zur Liste der klonbaren Typen hinzugefügt.
v14.5.0, v12.19.0KeyObject wurde der Liste der klonbaren Typen hinzugefügt.
v14.5.0, v12.19.0FileHandle wurde der Liste der übertragbaren Typen hinzugefügt.
v10.5.0Hinzugefügt in: v10.5.0

Sendet einen JavaScript-Wert an die Empfängerseite dieses Kanals. value wird auf eine Weise übertragen, die mit dem HTML-Algorithmus für strukturiertes Klonen kompatibel ist.

Insbesondere die wesentlichen Unterschiede zu JSON sind:

js
const { MessageChannel } = require('node:worker_threads')
const { port1, port2 } = new MessageChannel()

port1.on('message', message => console.log(message))

const circularData = {}
circularData.foo = circularData
// Gibt aus: { foo: [Circular] }
port2.postMessage(circularData)

transferList kann eine Liste von ArrayBuffer-, MessagePort- und FileHandle-Objekten sein. Nach der Übertragung sind sie auf der sendenden Seite des Kanals nicht mehr verwendbar (auch wenn sie nicht in value enthalten sind). Anders als bei Child-Prozessen wird die Übertragung von Handles wie Netzwerk-Sockets derzeit nicht unterstützt.

Wenn value SharedArrayBuffer-Instanzen enthält, sind diese von beiden Threads aus zugänglich. Sie können nicht in transferList aufgeführt werden.

value kann weiterhin ArrayBuffer-Instanzen enthalten, die nicht in transferList enthalten sind; in diesem Fall wird der zugrunde liegende Speicher kopiert und nicht verschoben.

js
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])
// Dies sendet eine Kopie von `uint8Array`:
port2.postMessage(uint8Array)
// Dies kopiert keine Daten, sondern macht `uint8Array` unbrauchbar:
port2.postMessage(uint8Array, [uint8Array.buffer])

// Der Speicher für `sharedUint8Array` ist sowohl vom
// Original als auch von der von `.on('message')` empfangenen Kopie
// zugänglich:
const sharedUint8Array = new Uint8Array(new SharedArrayBuffer(4))
port2.postMessage(sharedUint8Array)

// Dies überträgt einen neu erstellten Nachrichtenport an den Empfänger.
// Dies kann beispielsweise verwendet werden, um Kommunikationskanäle zwischen
// mehreren `Worker`-Threads zu erstellen, die Kinder desselben Eltern-Threads sind.
const otherChannel = new MessageChannel()
port2.postMessage({ port: otherChannel.port1 }, [otherChannel.port1])

Das Nachrichtobjekt wird sofort geklont und kann nach dem Senden ohne Seiteneffekte geändert werden.

Weitere Informationen zu den Serialisierungs- und Deserialisierungsmechanismen hinter dieser API finden Sie in der Serialisierungs-API des Moduls node:v8.

Überlegungen beim Übertragen von TypedArrays und Buffers

Alle TypedArray- und Buffer-Instanzen sind Ansichten über einen zugrunde liegenden ArrayBuffer. Das heißt, es ist der ArrayBuffer, der die Rohdaten tatsächlich speichert, während die TypedArray- und Buffer-Objekte eine Möglichkeit bieten, die Daten anzuzeigen und zu manipulieren. Es ist möglich und üblich, dass mehrere Ansichten über derselben ArrayBuffer-Instanz erstellt werden. Bei der Verwendung einer Übertragungsliste zum Übertragen eines ArrayBuffer ist große Vorsicht geboten, da dies dazu führt, dass alle TypedArray- und Buffer-Instanzen, die denselben ArrayBuffer verwenden, unbrauchbar werden.

js
const ab = new ArrayBuffer(10)

const u1 = new Uint8Array(ab)
const u2 = new Uint16Array(ab)

console.log(u2.length) // gibt 5 aus

port.postMessage(u1, [u1.buffer])

console.log(u2.length) // gibt 0 aus

Bei Buffer-Instanzen hängt insbesondere davon, wie die Instanzen erstellt wurden, ob der zugrunde liegende ArrayBuffer übertragen oder geklont werden kann, was oft nicht zuverlässig bestimmt werden kann.

Ein ArrayBuffer kann mit markAsUntransferable() gekennzeichnet werden, um anzugeben, dass er immer geklont und niemals übertragen werden soll.

Je nachdem, wie eine Buffer-Instanz erstellt wurde, besitzt sie möglicherweise ihren zugrunde liegenden ArrayBuffer oder auch nicht. Ein ArrayBuffer darf nur dann übertragen werden, wenn bekannt ist, dass die Buffer-Instanz ihn besitzt. Insbesondere bei Buffers, die aus dem internen Buffer-Pool erstellt wurden (z. B. mit Buffer.from() oder Buffer.allocUnsafe()), ist eine Übertragung nicht möglich und sie werden immer geklont, wodurch eine Kopie des gesamten Buffer-Pools gesendet wird. Dieses Verhalten kann mit unbeabsichtigter höherer Speichernutzung und möglichen Sicherheitsbedenken einhergehen.

Weitere Informationen zur Buffer-Poolbildung finden Sie unter Buffer.allocUnsafe().

Die ArrayBuffers für Buffer-Instanzen, die mit Buffer.alloc() oder Buffer.allocUnsafeSlow() erstellt wurden, können immer übertragen werden, aber dies führt dazu, dass alle anderen vorhandenen Ansichten dieser ArrayBuffers unbrauchbar werden.

Überlegungen beim Klonen von Objekten mit Prototypen, Klassen und Accessoren

Da das Klonen von Objekten den HTML-Strukturklon-Algorithmus verwendet, werden nicht aufzählbare Eigenschaften, Eigenschafts-Accessoren und Objektprototypen nicht beibehalten. Insbesondere werden Buffer-Objekte auf der Empfängerseite als einfache Uint8Arrays gelesen, und Instanzen von JavaScript-Klassen werden als einfache JavaScript-Objekte geklont.

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

// Gibt aus: { c: 3 }

Diese Einschränkung gilt auch für viele eingebaute Objekte, wie z. B. das globale URL-Objekt:

js
const { port1, port2 } = new MessageChannel()

port1.onmessage = ({ data }) => console.log(data)

port2.postMessage(new URL('https://example.org'))

// Gibt aus: { }

port.hasRef()

Hinzugefügt in: v18.1.0, v16.17.0

[Stabil: 1 - Experimentell]

Stabil: 1 Stabilität: 1 - Experimentell

Wenn true, hält das MessagePort-Objekt die Node.js-Ereignisschleife aktiv.

port.ref()

Hinzugefügt in: v10.5.0

Gegenteil von unref(). Das Aufrufen von ref() auf einem zuvor unref()ed-Port verhindert nicht, dass das Programm beendet wird, wenn es der einzige aktive Handle ist, der noch übrig ist (das Standardverhalten). Wenn der Port ref()ed ist, hat ein erneuter Aufruf von ref() keine Auswirkung.

Wenn Listener mit .on('message') angehängt oder entfernt werden, wird der Port automatisch ref()ed und unref()ed, je nachdem, ob Listener für das Ereignis existieren.

port.start()

Hinzugefügt in: v10.5.0

Startet den Empfang von Nachrichten an diesem MessagePort. Wenn dieser Port als Event-Emitter verwendet wird, wird dies automatisch aufgerufen, sobald 'message'-Listener angehängt werden.

Diese Methode existiert zur Parität mit der Web MessagePort API. In Node.js ist sie nur nützlich, um Nachrichten zu ignorieren, wenn kein Event-Listener vorhanden ist. Node.js weicht auch in der Behandlung von .onmessage ab. Das Setzen ruft automatisch .start() auf, aber das Aufheben der Einstellung lässt Nachrichten in der Warteschlange, bis ein neuer Handler gesetzt wird oder der Port verworfen wird.

port.unref()

Hinzugefügt in: v10.5.0

Das Aufrufen von unref() auf einem Port ermöglicht es dem Thread, zu beenden, wenn dies das einzige aktive Handle im Event-System ist. Wenn der Port bereits unref()ed ist, hat das erneute Aufrufen von unref() keine Auswirkung.

Wenn Listener mit .on('message') angehängt oder entfernt werden, wird der Port automatisch ref()ed und unref()ed, je nachdem, ob Listener für das Event existieren.

Klasse: Worker

Hinzugefügt in: v10.5.0

Die Klasse Worker repräsentiert einen unabhängigen JavaScript-Ausführungsthread. Die meisten Node.js APIs sind innerhalb dessen verfügbar.

Bemerkenswerte Unterschiede innerhalb einer Worker-Umgebung sind:

Das Erstellen von Worker-Instanzen innerhalb anderer Worker ist möglich.

Wie Web Worker und das node:cluster-Modul kann eine Zwei-Wege-Kommunikation durch die Übergabe von Nachrichten zwischen den Threads erreicht werden. Intern hat ein Worker ein eingebautes Paar von MessagePorts, die bereits miteinander verbunden sind, wenn der Worker erstellt wird. Während das MessagePort-Objekt auf der Elterseite nicht direkt exponiert wird, werden seine Funktionalitäten über worker.postMessage() und das worker.on('message') Event auf dem Worker-Objekt für den übergeordneten Thread exponiert.

Um benutzerdefinierte Nachrichtenkanäle zu erstellen (was gegenüber der Verwendung des globalen Standardkanals bevorzugt wird, da es die Trennung von Belangen erleichtert), können Benutzer ein MessageChannel-Objekt auf jedem Thread erstellen und einen der MessagePorts auf diesem MessageChannel über einen bereits vorhandenen Kanal, z. B. den globalen Kanal, an den anderen Thread übergeben.

Weitere Informationen darüber, wie Nachrichten übergeben werden und welche Art von JavaScript-Werten erfolgreich durch die Thread-Barriere transportiert werden können, finden Sie unter port.postMessage().

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

[Verlauf]

VersionÄnderungen
v19.8.0, v18.16.0Unterstützung für eine name-Option hinzugefügt, die es ermöglicht, dem Worker-Titel einen Namen für das Debugging hinzuzufügen.
v14.9.0Der Parameter filename kann ein WHATWG URL-Objekt mit dem data:-Protokoll sein.
v14.9.0Die Option trackUnmanagedFds wurde standardmäßig auf true gesetzt.
v14.6.0, v12.19.0Die Option trackUnmanagedFds wurde eingeführt.
v13.13.0, v12.17.0Die Option transferList wurde eingeführt.
v13.12.0, v12.17.0Der Parameter filename kann ein WHATWG URL-Objekt mit dem file:-Protokoll sein.
v13.4.0, v12.16.0Die Option argv wurde eingeführt.
v13.2.0, v12.16.0Die Option resourceLimits wurde eingeführt.
v10.5.0Hinzugefügt in: v10.5.0
  • filename <string> | <URL> Der Pfad zum Hauptskript oder Modul des Workers. Muss entweder ein absoluter Pfad oder ein relativer Pfad sein (d. h. relativ zum aktuellen Arbeitsverzeichnis), der mit ./ oder ../ beginnt, oder ein WHATWG URL-Objekt mit dem file:- oder data:-Protokoll. Bei Verwendung einer data: URL werden die Daten basierend auf dem MIME-Typ unter Verwendung des ECMAScript-Modulloaders interpretiert. Wenn options.eval true ist, handelt es sich um eine Zeichenfolge, die JavaScript-Code enthält, anstatt um einen Pfad.

  • options <Object>

    • argv <any[]> Liste von Argumenten, die in Zeichenketten umgewandelt und an process.argv im Worker angehängt werden. Dies ähnelt im Wesentlichen workerData, aber die Werte sind im globalen process.argv verfügbar, als wären sie als CLI-Optionen an das Skript übergeben worden.

    • env <Object> Wenn gesetzt, gibt den Anfangswert von process.env innerhalb des Worker-Threads an. Als Sonderwert kann worker.SHARE_ENV verwendet werden, um anzugeben, dass der übergeordnete Thread und der untergeordnete Thread ihre Umgebungsvariablen gemeinsam nutzen sollen; in diesem Fall wirken sich Änderungen am process.env-Objekt des einen Threads auch auf den anderen Thread aus. Standard: process.env.

    • eval <boolean> Wenn true und das erste Argument eine string ist, wird das erste Argument des Konstruktors als Skript interpretiert, das ausgeführt wird, sobald der Worker online ist.

    • execArgv <string[]> Liste der Node-CLI-Optionen, die an den Worker übergeben werden. V8-Optionen (wie --max-old-space-size) und Optionen, die den Prozess beeinflussen (wie --title), werden nicht unterstützt. Wenn gesetzt, wird dies als process.execArgv innerhalb des Workers bereitgestellt. Standardmäßig werden Optionen vom übergeordneten Thread geerbt.

    • stdin <boolean> Wenn dies auf true gesetzt ist, dann stellt worker.stdin einen beschreibbaren Stream bereit, dessen Inhalt als process.stdin innerhalb des Workers erscheint. Standardmäßig werden keine Daten bereitgestellt.

    • stdout <boolean> Wenn dies auf true gesetzt ist, dann wird worker.stdout nicht automatisch an process.stdout im übergeordneten Element weitergeleitet.

    • stderr <boolean> Wenn dies auf true gesetzt ist, dann wird worker.stderr nicht automatisch an process.stderr im übergeordneten Element weitergeleitet.

    • workerData <any> Jeder JavaScript-Wert, der geklont und als require('node:worker_threads').workerData verfügbar gemacht wird. Das Klonen erfolgt wie im HTML-Algorithmus für strukturiertes Klonen beschrieben, und es wird ein Fehler ausgelöst, wenn das Objekt nicht geklont werden kann (z. B. weil es functions enthält).

    • trackUnmanagedFds <boolean> Wenn dies auf true gesetzt ist, verfolgt der Worker rohe Dateideskriptoren, die durch fs.open() und fs.close() verwaltet werden, und schließt sie, wenn der Worker beendet wird, ähnlich wie andere Ressourcen wie Netzwerk-Sockets oder Dateideskriptoren, die durch die FileHandle-API verwaltet werden. Diese Option wird automatisch von allen verschachtelten Workers geerbt. Standard: true.

    • transferList <Object[]> Wenn ein oder mehrere MessagePort-ähnliche Objekte in workerData übergeben werden, ist eine transferList für diese Elemente erforderlich, andernfalls wird ERR_MISSING_MESSAGE_PORT_IN_TRANSFER_LIST ausgelöst. Siehe port.postMessage() für weitere Informationen.

    • resourceLimits <Object> Ein optionales Set von Ressourcenbeschränkungen für die neue JS-Engine-Instanz. Das Erreichen dieser Grenzwerte führt zur Beendigung der Worker-Instanz. Diese Grenzwerte wirken sich nur auf die JS-Engine aus und nicht auf externe Daten, einschließlich keine ArrayBuffers. Selbst wenn diese Grenzwerte gesetzt sind, kann der Prozess immer noch abgebrochen werden, wenn eine globale Situation mit unzureichendem Speicher auftritt.

    • maxOldGenerationSizeMb <number> Die maximale Größe des Haupt-Heaps in MB. Wenn das Befehlszeilenargument --max-old-space-size gesetzt ist, überschreibt es diese Einstellung.

    • maxYoungGenerationSizeMb <number> Die maximale Größe eines Heap-Bereichs für kürzlich erstellte Objekte. Wenn das Befehlszeilenargument --max-semi-space-size gesetzt ist, überschreibt es diese Einstellung.

    • codeRangeSizeMb <number> Die Größe eines vorab zugewiesenen Speicherbereichs, der für generierten Code verwendet wird.

    • stackSizeMb <number> Die standardmäßige maximale Stackgröße für den Thread. Kleine Werte können zu unbrauchbaren Worker-Instanzen führen. Standard: 4.

    • name <string> Ein optionaler name, der dem Worker-Titel für Debugging-/Identifizierungszwecke angehängt wird, wodurch der endgültige Titel als [worker ${id}] ${name} lautet. Standard: ''.

Ereignis: 'error'

Hinzugefügt in: v10.5.0

Das Ereignis 'error' wird ausgelöst, wenn der Worker-Thread eine nicht abgefangene Ausnahme wirft. In diesem Fall wird der Worker beendet.

Ereignis: 'exit'

Hinzugefügt in: v10.5.0

Das Ereignis 'exit' wird ausgelöst, sobald der Worker angehalten wurde. Wenn der Worker durch Aufruf von process.exit() beendet wurde, ist der Parameter exitCode der übergebene Exit-Code. Wenn der Worker beendet wurde, ist der Parameter exitCode 1.

Dies ist das letzte Ereignis, das von einer Worker-Instanz ausgelöst wird.

Ereignis: 'message'

Hinzugefügt in: v10.5.0

  • value <any> Der übertragene Wert

Das Ereignis 'message' wird ausgelöst, wenn der Worker-Thread require('node:worker_threads').parentPort.postMessage() aufgerufen hat. Weitere Details finden Sie im Ereignis port.on('message').

Alle vom Worker-Thread gesendeten Nachrichten werden ausgelöst, bevor das Ereignis 'exit' auf dem Worker-Objekt ausgelöst wird.

Ereignis: 'messageerror'

Hinzugefügt in: v14.5.0, v12.19.0

Das Ereignis 'messageerror' wird ausgelöst, wenn die Deserialisierung einer Nachricht fehlgeschlagen ist.

Ereignis: 'online'

Hinzugefügt in: v10.5.0

Das Ereignis 'online' wird ausgelöst, wenn der Worker-Thread mit der Ausführung von JavaScript-Code begonnen hat.

worker.getHeapSnapshot([options])

[Verlauf]

VersionÄnderungen
v19.1.0Unterstützung für Optionen zum Konfigurieren des Heap-Snapshots.
v13.9.0, v12.17.0Hinzugefügt in: v13.9.0, v12.17.0
  • options <Object>

    • exposeInternals <boolean> Wenn true, interne Informationen im Heap-Snapshot freigeben. Standard: false.
    • exposeNumericValues <boolean> Wenn true, numerische Werte in künstlichen Feldern freigeben. Standard: false.
  • Gibt zurück: <Promise> Eine Promise für einen lesbaren Stream, der einen V8-Heap-Snapshot enthält

Gibt einen lesbaren Stream für einen V8-Snapshot des aktuellen Zustands des Workers zurück. Weitere Informationen finden Sie unter v8.getHeapSnapshot().

Wenn der Worker-Thread nicht mehr ausgeführt wird, was vor dem Auslösen des Ereignisses 'exit' eintreten kann, wird die zurückgegebene Promise sofort mit einem Fehler ERR_WORKER_NOT_RUNNING abgelehnt.

worker.performance

Hinzugefügt in: v15.1.0, v14.17.0, v12.22.0

Ein Objekt, das verwendet werden kann, um Leistungsinformationen von einer Worker-Instanz abzufragen. Ähnlich wie perf_hooks.performance.

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

Hinzugefügt in: v15.1.0, v14.17.0, v12.22.0

  • utilization1 <Object> Das Ergebnis eines vorherigen Aufrufs von eventLoopUtilization().
  • utilization2 <Object> Das Ergebnis eines vorherigen Aufrufs von eventLoopUtilization() vor utilization1.
  • Gibt zurück: <Object>

Der gleiche Aufruf wie perf_hooks eventLoopUtilization(), außer dass die Werte der Worker-Instanz zurückgegeben werden.

Ein Unterschied besteht darin, dass das Bootstrapping innerhalb eines Workers im Gegensatz zum Hauptthread innerhalb der Event-Schleife erfolgt. Die Event-Schleifen-Auslastung ist also sofort verfügbar, sobald das Skript des Workers mit der Ausführung beginnt.

Eine idle-Zeit, die nicht ansteigt, deutet nicht darauf hin, dass der Worker im Bootstrap hängen geblieben ist. Die folgenden Beispiele zeigen, wie die gesamte Lebensdauer des Workers nie idle-Zeit ansammelt, aber dennoch in der Lage ist, Nachrichten zu verarbeiten.

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

Die Event-Schleifen-Auslastung eines Workers ist erst verfügbar, nachdem das Ereignis 'online' ausgelöst wurde, und wenn sie davor oder nach dem Ereignis 'exit' aufgerufen wird, haben alle Eigenschaften den Wert 0.

worker.postMessage(value[, transferList])

Hinzugefügt in: v10.5.0

Sendet eine Nachricht an den Worker, die über require('node:worker_threads').parentPort.on('message') empfangen wird. Siehe port.postMessage() für weitere Details.

worker.ref()

Hinzugefügt in: v10.5.0

Das Gegenteil von unref(). Der Aufruf von ref() auf einem zuvor unref()-ten Worker führt nicht dazu, dass das Programm beendet wird, wenn dies der einzig aktive Handle ist (das Standardverhalten). Wenn der Worker ref()-iert ist, hat ein erneuter Aufruf von ref() keine Auswirkung.

worker.resourceLimits

Hinzugefügt in: v13.2.0, v12.16.0

Stellt die Menge an Ressourcenbeschränkungen der JS-Engine für diesen Worker-Thread bereit. Wenn die Option resourceLimits an den Worker-Konstruktor übergeben wurde, entspricht dies seinen Werten.

Wenn der Worker angehalten wurde, ist der Rückgabewert ein leeres Objekt.

worker.stderr

Hinzugefügt in: v10.5.0

Dies ist ein lesbarer Stream, der Daten enthält, die in process.stderr innerhalb des Worker-Threads geschrieben wurden. Wenn stderr: true nicht an den Worker-Konstruktor übergeben wurde, werden die Daten an den process.stderr-Stream des übergeordneten Threads weitergeleitet.

worker.stdin

Hinzugefügt in: v10.5.0

Wenn stdin: true an den Worker-Konstruktor übergeben wurde, ist dies ein beschreibbarer Stream. Die in diesen Stream geschriebenen Daten werden im Worker-Thread als process.stdin zur Verfügung gestellt.

worker.stdout

Hinzugefügt in: v10.5.0

Dies ist ein lesbarer Stream, der Daten enthält, die in process.stdout innerhalb des Worker-Threads geschrieben wurden. Wenn stdout: true nicht an den Worker-Konstruktor übergeben wurde, werden die Daten in den process.stdout-Stream des übergeordneten Threads geleitet.

worker.terminate()

[Verlauf]

VersionÄnderungen
v12.5.0Diese Funktion gibt nun eine Promise zurück. Das Übergeben eines Callbacks ist veraltet und war bis zu dieser Version nutzlos, da der Worker tatsächlich synchron beendet wurde. Die Beendigung ist nun eine vollständig asynchrone Operation.
v10.5.0Hinzugefügt in: v10.5.0

Stoppt die gesamte JavaScript-Ausführung im Worker-Thread so schnell wie möglich. Gibt eine Promise für den Exit-Code zurück, die erfüllt wird, wenn das Ereignis 'exit' event ausgelöst wird.

worker.threadId

Hinzugefügt in: v10.5.0

Eine Ganzzahlkennung für den referenzierten Thread. Innerhalb des Worker-Threads ist sie als require('node:worker_threads').threadId verfügbar. Dieser Wert ist für jede Worker-Instanz innerhalb eines einzelnen Prozesses eindeutig.

worker.unref()

Hinzugefügt in: v10.5.0

Das Aufrufen von unref() auf einem Worker ermöglicht es dem Thread, sich zu beenden, wenn dies das einzige aktive Handle im Ereignissystem ist. Wenn der Worker bereits unref()ed ist, hat ein erneuter Aufruf von unref() keine Auswirkungen.

Hinweise

Synchrone Blockierung von stdio

Worker verwenden Message Passing über <MessagePort>, um Interaktionen mit stdio zu implementieren. Dies bedeutet, dass stdio-Ausgaben, die von einem Worker stammen, durch synchronen Code am empfangenden Ende blockiert werden können, der die Node.js-Ereignisschleife blockiert.

js
import { Worker, isMainThread } from 'node:worker_threads'

if (isMainThread) {
  new Worker(new URL(import.meta.url))
  for (let n = 0; n < 1e10; n++) {
    // Schleife zur Simulation von Arbeit.
  }
} else {
  // Diese Ausgabe wird durch die for-Schleife im Hauptthread blockiert.
  console.log('foo')
}
js
'use strict'

const { Worker, isMainThread } = require('node:worker_threads')

if (isMainThread) {
  new Worker(__filename)
  for (let n = 0; n < 1e10; n++) {
    // Schleife zur Simulation von Arbeit.
  }
} else {
  // Diese Ausgabe wird durch die for-Schleife im Hauptthread blockiert.
  console.log('foo')
}

Starten von Worker-Threads aus Preload-Skripten

Seien Sie vorsichtig beim Starten von Worker-Threads aus Preload-Skripten (Skripte, die mit dem Befehlszeilenparameter -r geladen und ausgeführt werden). Sofern die Option execArgv nicht explizit gesetzt wird, übernehmen neue Worker-Threads automatisch die Befehlszeilenparameter vom laufenden Prozess und laden die gleichen Preload-Skripte wie der Hauptthread. Wenn das Preload-Skript bedingungslos einen Worker-Thread startet, wird jeder erzeugte Thread einen weiteren erzeugen, bis die Anwendung abstürzt.