Skip to content

Threads de travail

[Stable : 2 - Stable]

Stable : 2 Stabilité : 2 - Stable

Code source : lib/worker_threads.js

Le module node:worker_threads permet l'utilisation de threads qui exécutent JavaScript en parallèle. Pour y accéder :

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

Les Workers (threads) sont utiles pour effectuer des opérations JavaScript gourmandes en CPU. Ils n'aident pas beaucoup avec les tâches gourmandes en E/S. Les opérations d'E/S asynchrones intégrées de Node.js sont plus efficaces que ce que les Workers peuvent être.

Contrairement à child_process ou cluster, worker_threads peut partager la mémoire. Ils le font en transférant des instances ArrayBuffer ou en partageant des instances SharedArrayBuffer.

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 stopped with exit code ${code}`))
      })
    })
  }
} else {
  const { parse } = require('some-js-parsing-library')
  const script = workerData
  parentPort.postMessage(parse(script))
}

L'exemple ci-dessus génère un thread Worker pour chaque appel parseJSAsync(). En pratique, utilisez un pool de Workers pour ce type de tâches. Sinon, les frais généraux de création de Workers dépasseraient probablement leurs avantages.

Lors de la mise en œuvre d'un pool de workers, utilisez l'API AsyncResource pour informer les outils de diagnostic (par exemple, pour fournir des traces de pile asynchrones) de la corrélation entre les tâches et leurs résultats. Voir "Utilisation de AsyncResource pour un pool de threads Worker" dans la documentation async_hooks pour un exemple d'implémentation.

Les threads Worker héritent par défaut des options non spécifiques au processus. Reportez-vous à Options du constructeur Worker pour savoir comment personnaliser les options des threads Worker, en particulier les options argv et execArgv.

worker.getEnvironmentData(key)

[Historique]

VersionModifications
v17.5.0, v16.15.0N'est plus expérimental.
v15.12.0, v14.18.0Ajouté dans : v15.12.0, v14.18.0
  • key <any> Toute valeur JavaScript arbitraire et clonable pouvant servir de clé <Map>.
  • Retourne : <any>

Dans un thread worker, worker.getEnvironmentData() retourne un clone des données passées au thread de génération worker.setEnvironmentData(). Chaque nouveau Worker reçoit automatiquement sa propre copie des données d'environnement.

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

if (isMainThread) {
  setEnvironmentData('Hello', 'World!')
  const worker = new Worker(__filename)
} else {
  console.log(getEnvironmentData('Hello')) // Affiche 'World!'.
}

worker.isMainThread

Ajouté dans : v10.5.0

Est égal à true si ce code ne s'exécute pas à l'intérieur d'un thread Worker.

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

if (isMainThread) {
  // Ceci recharge le fichier actuel à l'intérieur d'une instance Worker.
  new Worker(__filename)
} else {
  console.log('Inside Worker!')
  console.log(isMainThread) // Affiche 'false'.
}

worker.markAsUntransferable(object)

Ajouté dans : v14.5.0, v12.19.0

  • object <any> Toute valeur JavaScript arbitraire.

Marquer un objet comme non transférable. Si object apparaît dans la liste de transfert d'un appel port.postMessage(), une erreur est levée. Il s'agit d'une opération sans effet si object est une valeur primitive.

En particulier, cela a du sens pour les objets qui peuvent être clonés, plutôt que transférés, et qui sont utilisés par d'autres objets du côté envoyeur. Par exemple, Node.js marque les ArrayBuffer qu'il utilise pour son pool Buffer avec ceci.

Cette opération est irréversible.

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 {
  // Ceci lèvera une erreur, car pooledBuffer n'est pas transférable.
  port1.postMessage(typedArray1, [typedArray1.buffer])
} catch (error) {
  // error.name === 'DataCloneError'
}

// La ligne suivante affiche le contenu de typedArray1 -- il possède toujours
// sa mémoire et n'a pas été transféré. Sans
// `markAsUntransferable()`, ceci afficherait un Uint8Array vide et l'appel
// postMessage aurait réussi.
// typedArray2 est également intact.
console.log(typedArray1)
console.log(typedArray2)

Il n'existe pas d'équivalent à cette API dans les navigateurs.

worker.isMarkedAsUntransferable(object)

Ajouté dans : v21.0.0

Vérifie si un objet est marqué comme non transférable avec markAsUntransferable().

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

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

isMarkedAsUntransferable(pooledBuffer) // Retourne true.

Il n’existe pas d’équivalent à cette API dans les navigateurs.

worker.markAsUncloneable(object)

Ajouté dans : v23.0.0

  • object <any> Toute valeur JavaScript arbitraire.

Marque un objet comme non clonable. Si object est utilisé comme message dans un appel port.postMessage(), une erreur est levée. Ceci est une opération sans effet si object est une valeur primitive.

Ceci n’a aucun effet sur ArrayBuffer, ou tout objet de type Buffer.

Cette opération est irréversible.

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

const anyObject = { foo: 'bar' }
markAsUncloneable(anyObject)
const { port1 } = new MessageChannel()
try {
  // Ceci lèvera une erreur, car anyObject n’est pas clonable.
  port1.postMessage(anyObject)
} catch (error) {
  // error.name === 'DataCloneError'
}

Il n’existe pas d’équivalent à cette API dans les navigateurs.

worker.moveMessagePortToContext(port, contextifiedSandbox)

Ajouté dans : v11.13.0

Transfère un MessagePort vers un contexte vm différent. L’objet port original devient inutilisable, et l’instance MessagePort retournée prend sa place.

Le MessagePort retourné est un objet dans le contexte cible et hérite de sa classe globale Object. Les objets passés à l’écouteur port.onmessage() sont également créés dans le contexte cible et héritent de sa classe globale Object.

Cependant, le MessagePort créé n’hérite plus de EventTarget, et seul port.onmessage() peut être utilisé pour recevoir des événements en l’utilisant.

worker.parentPort

Ajouté dans : v10.5.0

Si ce thread est un Worker, il s'agit d'un MessagePort permettant la communication avec le thread parent. Les messages envoyés à l'aide de parentPort.postMessage() sont disponibles dans le thread parent à l'aide de worker.on('message'), et les messages envoyés depuis le thread parent à l'aide de worker.postMessage() sont disponibles dans ce thread à l'aide de parentPort.on('message').

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

if (isMainThread) {
  const worker = new Worker(__filename)
  worker.once('message', message => {
    console.log(message) // Affiche 'Hello, world!'.
  })
  worker.postMessage('Hello, world!')
} else {
  // Lorsqu'un message du thread parent est reçu, renvoyez-le :
  parentPort.once('message', message => {
    parentPort.postMessage(message)
  })
}

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

Ajouté dans : v22.5.0

[Stable : 1 - Expérimental]

Stable : 1 Stabilité : 1.1 - Développement actif

Envoie une valeur à un autre travailleur, identifié par son ID de thread.

Si le thread cible n'a aucun écouteur pour l'événement workerMessage, l'opération lèvera une erreur ERR_WORKER_MESSAGING_FAILED.

Si le thread cible a levé une erreur lors du traitement de l'événement workerMessage, l'opération lèvera une erreur ERR_WORKER_MESSAGING_ERRORED.

Cette méthode doit être utilisée lorsque le thread cible n'est pas le parent ou l'enfant direct du thread actuel. Si les deux threads sont parents-enfants, utilisez require('node:worker_threads').parentPort.postMessage() et worker.postMessage() pour permettre aux threads de communiquer.

L'exemple ci-dessous montre l'utilisation de postMessageToThread : il crée 10 threads imbriqués, le dernier essaiera de communiquer avec le thread principal.

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)

[Historique]

VersionModifications
v15.12.0L'argument port peut désormais également faire référence à un BroadcastChannel.
v12.3.0Ajouté dans : v12.3.0

Reçoit un seul message d'un MessagePort donné. Si aucun message n'est disponible, undefined est retourné, sinon un objet avec une seule propriété message contenant la charge utile du message, correspondant au message le plus ancien de la file d'attente du MessagePort.

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

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

Lorsque cette fonction est utilisée, aucun événement 'message' n'est émis et le gestionnaire onmessage n'est pas appelé.

worker.resourceLimits

Ajouté dans : v13.2.0, v12.16.0

Fournit l'ensemble des contraintes de ressources du moteur JS dans ce thread Worker. Si l'option resourceLimits a été passée au constructeur Worker, cela correspond à ses valeurs.

Si cela est utilisé dans le thread principal, sa valeur est un objet vide.

worker.SHARE_ENV

Ajouté dans : v11.14.0

Une valeur spéciale pouvant être passée en tant qu’option env du constructeur Worker, pour indiquer que le thread actuel et le thread Worker doivent partager un accès en lecture et en écriture au même ensemble de variables d’environnement.

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) // Affiche 'foo'.
})

worker.setEnvironmentData(key[, value])

[Historique]

VersionModifications
v17.5.0, v16.15.0N’est plus expérimental.
v15.12.0, v14.18.0Ajouté dans : v15.12.0, v14.18.0
  • key <any> Toute valeur JavaScript arbitraire et clonable pouvant être utilisée comme clé <Map>.
  • value <any> Toute valeur JavaScript arbitraire et clonable qui sera clonée et passée automatiquement à toutes les nouvelles instances Worker. Si value est passé comme undefined, toute valeur précédemment définie pour la clé key sera supprimée.

L’API worker.setEnvironmentData() définit le contenu de worker.getEnvironmentData() dans le thread actuel et toutes les nouvelles instances Worker générées à partir du contexte actuel.

worker.threadId

Ajouté dans : v10.5.0

Un identifiant entier pour le thread actuel. Sur l’objet worker correspondant (le cas échéant), il est disponible sous la forme worker.threadId. Cette valeur est unique pour chaque instance Worker au sein d’un seul processus.

worker.workerData

Ajouté dans : v10.5.0

Une valeur JavaScript arbitraire qui contient un clone des données passées au constructeur Worker de ce thread.

Les données sont clonées comme si on utilisait postMessage(), conformément à l'algorithme de clonage structuré HTML.

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

if (isMainThread) {
  const worker = new Worker(__filename, { workerData: 'Hello, world!' })
} else {
  console.log(workerData) // Affiche 'Hello, world!'.
}

Classe : BroadcastChannel extends EventTarget

[Historique]

VersionModifications
v18.0.0N'est plus expérimental.
v15.4.0Ajouté dans : v15.4.0

Les instances de BroadcastChannel permettent une communication asynchrone un-à-plusieurs avec toutes les autres instances de BroadcastChannel liées au même nom de canal.

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('hello from every worker')
  bc.close()
}

new BroadcastChannel(name)

Ajouté dans : v15.4.0

  • name <any> Le nom du canal auquel se connecter. Toute valeur JavaScript pouvant être convertie en chaîne de caractères à l'aide de ${name} est autorisée.

broadcastChannel.close()

Ajouté dans : v15.4.0

Ferme la connexion BroadcastChannel.

broadcastChannel.onmessage

Ajouté dans : v15.4.0

  • Type : <Function> Appelée avec un seul argument MessageEvent lorsqu'un message est reçu.

broadcastChannel.onmessageerror

Ajouté dans : v15.4.0

  • Type : <Function> Invoqué lorsqu'un message reçu ne peut pas être désérialisé.

broadcastChannel.postMessage(message)

Ajouté dans : v15.4.0

  • message <any> Toute valeur JavaScript clonable.

broadcastChannel.ref()

Ajouté dans : v15.4.0

Opposé de unref(). Appeler ref() sur un BroadcastChannel précédemment unref() ne permet pas au programme de se terminer s'il s'agit de la seule poignée active restante (comportement par défaut). Si le port est ref()é, appeler ref() à nouveau n'a aucun effet.

broadcastChannel.unref()

Ajouté dans : v15.4.0

Appeler unref() sur un BroadcastChannel permet au thread de se terminer s'il s'agit de la seule poignée active dans le système d'événements. Si le BroadcastChannel est déjà unref()é, appeler unref() à nouveau n'a aucun effet.

Classe : MessageChannel

Ajouté dans : v10.5.0

Les instances de la classe worker.MessageChannel représentent un canal de communication bidirectionnel asynchrone. MessageChannel n'a pas de méthodes propres. new MessageChannel() renvoie un objet avec les propriétés port1 et port2, qui font référence à des instances liées de MessagePort.

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

const { port1, port2 } = new MessageChannel()
port1.on('message', message => console.log('received', message))
port2.postMessage({ foo: 'bar' })
// Affiche : received { foo: 'bar' } depuis le listener `port1.on('message')`

Classe : MessagePort

[Historique]

VersionModifications
v14.7.0Cette classe hérite maintenant de EventTarget plutôt que de EventEmitter.
v10.5.0Ajouté dans : v10.5.0

Les instances de la classe worker.MessagePort représentent une extrémité d'un canal de communication bidirectionnel asynchrone. Il peut être utilisé pour transférer des données structurées, des régions de mémoire et d'autres MessagePort entre différents Worker.

Cette implémentation correspond aux MessagePort du navigateur.

Événement : 'close'

Ajouté dans : v10.5.0

L'événement 'close' est émis une fois que l'un ou l'autre côté du canal a été déconnecté.

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

// Affiche :
//   foobar
//   fermé !
port2.on('message', message => console.log(message))
port2.on('close', () => console.log('fermé !'))

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

Événement : 'message'

Ajouté dans : v10.5.0

  • value <any> La valeur transmise

L'événement 'message' est émis pour tout message entrant, contenant l'entrée clonée de port.postMessage().

Les écouteurs de cet événement reçoivent un clone du paramètre value tel que passé à postMessage() et aucun autre argument.

Événement : 'messageerror'

Ajouté dans : v14.5.0, v12.19.0

L'événement 'messageerror' est émis lorsque la désérialisation d'un message a échoué.

Actuellement, cet événement est émis lorsqu'une erreur se produit lors de l'instanciation de l'objet JS publié sur le côté récepteur. De telles situations sont rares, mais peuvent se produire, par exemple, lorsque certains objets de l'API Node.js sont reçus dans un vm.Context (où les API Node.js ne sont actuellement pas disponibles).

port.close()

Ajouté dans : v10.5.0

Désactive l'envoi ultérieur de messages de l'un ou l'autre côté de la connexion. Cette méthode peut être appelée lorsqu'aucune autre communication n'aura lieu via ce MessagePort.

L'événement 'close' est émis sur les deux instances MessagePort qui font partie du canal.

port.postMessage(value[, transferList])

[Historique]

VersionModifications
v21.0.0Une erreur est levée lorsqu'un objet non transférable est dans la liste de transfert.
v15.6.0Ajout de X509Certificate à la liste des types clonables.
v15.0.0Ajout de CryptoKey à la liste des types clonables.
v15.14.0, v14.18.0Ajout de 'BlockList' à la liste des types clonables.
v15.9.0, v14.18.0Ajout des types 'Histogram' à la liste des types clonables.
v14.5.0, v12.19.0Ajout de KeyObject à la liste des types clonables.
v14.5.0, v12.19.0Ajout de FileHandle à la liste des types transférables.
v10.5.0Ajouté dans : v10.5.0

Envoie une valeur JavaScript au côté récepteur de ce canal. value est transféré d'une manière compatible avec l'algorithme de clonage structuré HTML.

En particulier, les différences significatives par rapport à JSON sont :

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

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

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

transferList peut être une liste d'objets ArrayBuffer, MessagePort et FileHandle. Après le transfert, ils ne sont plus utilisables du côté envoi du canal (même s'ils ne sont pas contenus dans value). Contrairement aux processus enfants, le transfert de handles tels que les sockets réseau n'est actuellement pas pris en charge.

Si value contient des instances de SharedArrayBuffer, celles-ci sont accessibles depuis l'un ou l'autre thread. Elles ne peuvent pas être listées dans transferList.

value peut toujours contenir des instances ArrayBuffer qui ne sont pas dans transferList ; dans ce cas, la mémoire sous-jacente est copiée plutôt que déplacée.

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])
// Ceci publie une copie de `uint8Array` :
port2.postMessage(uint8Array)
// Ceci ne copie pas les données, mais rend `uint8Array` inutilisable :
port2.postMessage(uint8Array, [uint8Array.buffer])

// La mémoire pour `sharedUint8Array` est accessible à la fois depuis l'original
// et la copie reçue par `.on('message')` :
const sharedUint8Array = new Uint8Array(new SharedArrayBuffer(4))
port2.postMessage(sharedUint8Array)

// Ceci transfère un port de message nouvellement créé au récepteur.
// Ceci peut être utilisé, par exemple, pour créer des canaux de communication entre
// plusieurs threads `Worker` qui sont enfants du même thread parent.
const otherChannel = new MessageChannel()
port2.postMessage({ port: otherChannel.port1 }, [otherChannel.port1])

L'objet message est cloné immédiatement et peut être modifié après la publication sans avoir d'effets secondaires.

Pour plus d'informations sur les mécanismes de sérialisation et de désérialisation derrière cette API, consultez l'API de sérialisation du module node:v8.

Considérations lors du transfert de TypedArrays et de Buffers

Toutes les instances de TypedArray et de Buffer sont des vues sur un ArrayBuffer sous-jacent. C'est-à-dire que c'est l'ArrayBuffer qui stocke réellement les données brutes, tandis que les objets TypedArray et Buffer fournissent un moyen de visualiser et de manipuler les données. Il est possible et courant de créer plusieurs vues sur la même instance d'ArrayBuffer. Il faut faire très attention lors de l'utilisation d'une liste de transfert pour transférer un ArrayBuffer, car cela rend inutilisables toutes les instances de TypedArray et de Buffer qui partagent ce même ArrayBuffer.

js
const ab = new ArrayBuffer(10)

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

console.log(u2.length) // affiche 5

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

console.log(u2.length) // affiche 0

Pour les instances de Buffer, plus précisément, la possibilité de transférer ou de cloner l'ArrayBuffer sous-jacent dépend entièrement de la façon dont les instances ont été créées, ce qui ne peut souvent pas être déterminé de manière fiable.

Un ArrayBuffer peut être marqué avec markAsUntransferable() pour indiquer qu'il doit toujours être cloné et jamais transféré.

Selon la façon dont une instance de Buffer a été créée, il se peut qu'elle possède ou non son ArrayBuffer sous-jacent. Un ArrayBuffer ne doit pas être transféré à moins qu'il ne soit connu que l'instance Buffer le possède. En particulier, pour les Buffer créés à partir du pool interne Buffer (en utilisant, par exemple, Buffer.from() ou Buffer.allocUnsafe()), leur transfert n'est pas possible et ils sont toujours clonés, ce qui envoie une copie de l'ensemble du pool Buffer. Ce comportement peut entraîner une utilisation de la mémoire plus élevée et des problèmes de sécurité imprévus.

Voir Buffer.allocUnsafe() pour plus de détails sur la mise en commun des Buffer.

Les ArrayBuffer pour les instances de Buffer créées à l'aide de Buffer.alloc() ou Buffer.allocUnsafeSlow() peuvent toujours être transférées, mais cela rend inutilisables toutes les autres vues existantes de ces ArrayBuffer.

Considérations lors du clonage d'objets avec prototypes, classes et accesseurs

Le clonage d'objets utilise l'algorithme de clonage structuré HTML Structured clone algorithm, les propriétés non énumérables, les accesseurs de propriétés et les prototypes d'objets ne sont pas préservés. En particulier, les objets Buffer seront lus comme des Uint8Array simples du côté récepteur, et les instances de classes JavaScript seront clonées comme des objets JavaScript simples.

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

// Affiche : { c: 3 }

Cette limitation s'étend à de nombreux objets intégrés, tels que l'objet global URL :

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

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

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

// Affiche : { }

port.hasRef()

Ajouté dans : v18.1.0, v16.17.0

[Stable : 1 - Expérimental]

Stable : 1 Stabilité : 1 - Expérimental

Si vrai, l'objet MessagePort maintiendra la boucle d'événements Node.js active.

port.ref()

Ajouté dans : v10.5.0

Opposé de unref(). Appeler ref() sur un port précédemment unref() ne permet pas au programme de se terminer s'il s'agit de la seule poignée active restante (comportement par défaut). Si le port est ref(), appeler ref() à nouveau n'a aucun effet.

Si des écouteurs sont attachés ou supprimés à l'aide de .on('message'), le port est ref() et unref() automatiquement selon que des écouteurs pour l'événement existent.

port.start()

Ajouté dans : v10.5.0

Commence à recevoir des messages sur ce MessagePort. Lorsque ce port est utilisé comme émetteur d'événements, cela est appelé automatiquement une fois que les écouteurs 'message' sont attachés.

Cette méthode existe pour la parité avec l'API Web MessagePort. Dans Node.js, elle n'est utile que pour ignorer les messages lorsqu'aucun écouteur d'événements n'est présent. Node.js diverge également dans sa gestion de .onmessage. Sa définition appelle automatiquement .start(), mais sa suppression permet aux messages de s'accumuler jusqu'à ce qu'un nouveau gestionnaire soit défini ou que le port soit supprimé.

port.unref()

Ajouté dans : v10.5.0

Appeler unref() sur un port permet au thread de sortir si c'est la seule poignée active dans le système d'événements. Si le port est déjà unref(), appeler unref() à nouveau n'a aucun effet.

Si des écouteurs sont attachés ou supprimés à l'aide de .on('message'), le port est ref() et unref() automatiquement en fonction de l'existence d'écouteurs pour l'événement.

Classe : Worker

Ajouté dans : v10.5.0

La classe Worker représente un thread d'exécution JavaScript indépendant. La plupart des API Node.js sont disponibles à l'intérieur.

Différences notables dans un environnement Worker :

La création d'instances Worker à l'intérieur d'autres Worker est possible.

Comme les Web Workers et le module node:cluster, une communication bidirectionnelle peut être réalisée grâce à l'échange de messages inter-threads. En interne, un Worker possède une paire intégrée de MessagePort qui sont déjà associés l'un à l'autre lors de la création du Worker. Bien que l'objet MessagePort du côté parent ne soit pas directement exposé, ses fonctionnalités sont exposées via worker.postMessage() et l'événement worker.on('message') sur l'objet Worker pour le thread parent.

Pour créer des canaux de messagerie personnalisés (ce qui est encouragé par rapport à l'utilisation du canal global par défaut car cela facilite la séparation des préoccupations), les utilisateurs peuvent créer un objet MessageChannel sur l'un ou l'autre thread et transmettre l'un des MessagePort de ce MessageChannel à l'autre thread via un canal préexistant, tel que le canal global.

Voir port.postMessage() pour plus d'informations sur la manière dont les messages sont transmis et sur le type de valeurs JavaScript qui peuvent être transportées avec succès à travers la barrière des threads.

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

[Historique]

VersionModifications
v19.8.0, v18.16.0Ajout de la prise en charge d'une option name, permettant d'ajouter un nom au titre du worker pour le débogage.
v14.9.0Le paramètre filename peut être un objet URL WHATWG utilisant le protocole data:.
v14.9.0L'option trackUnmanagedFds était définie sur true par défaut.
v14.6.0, v12.19.0L'option trackUnmanagedFds a été introduite.
v13.13.0, v12.17.0L'option transferList a été introduite.
v13.12.0, v12.17.0Le paramètre filename peut être un objet URL WHATWG utilisant le protocole file:.
v13.4.0, v12.16.0L'option argv a été introduite.
v13.2.0, v12.16.0L'option resourceLimits a été introduite.
v10.5.0Ajouté dans : v10.5.0
  • filename <string> | <URL> Le chemin vers le script principal ou le module du Worker. Doit être soit un chemin absolu, soit un chemin relatif (c'est-à-dire relatif au répertoire de travail actuel) commençant par ./ ou ../, soit un objet URL WHATWG utilisant le protocole file: ou data:. Lors de l'utilisation d'une URL data:, les données sont interprétées en fonction du type MIME à l'aide du chargeur de modules ECMAScript. Si options.eval est true, il s'agit d'une chaîne contenant du code JavaScript plutôt qu'un chemin.

  • options <Object>

    • argv <any[]> Liste d'arguments qui seraient mis en chaîne et ajoutés à process.argv dans le worker. Ceci est assez similaire à workerData, mais les valeurs sont disponibles sur le process.argv global comme si elles étaient passées comme options CLI au script.

    • env <Object> Si défini, spécifie la valeur initiale de process.env dans le thread Worker. En tant que valeur spéciale, worker.SHARE_ENV peut être utilisé pour spécifier que le thread parent et le thread enfant doivent partager leurs variables d'environnement ; dans ce cas, les modifications apportées à l'objet process.env d'un thread affectent également l'autre thread. Par défaut : process.env.

    • eval <boolean> Si true et que le premier argument est une string, interpréter le premier argument du constructeur comme un script qui est exécuté une fois le worker en ligne.

    • execArgv <string[]> Liste des options CLI de nœud passées au worker. Les options V8 (telles que --max-old-space-size) et les options qui affectent le processus (telles que --title) ne sont pas prises en charge. Si défini, ceci est fourni comme process.execArgv dans le worker. Par défaut, les options sont héritées du thread parent.

    • stdin <boolean> Si ceci est défini sur true, alors worker.stdin fournit un flux inscriptible dont le contenu apparaît comme process.stdin dans le Worker. Par défaut, aucune donnée n'est fournie.

    • stdout <boolean> Si ceci est défini sur true, alors worker.stdout n'est pas automatiquement acheminé vers process.stdout dans le parent.

    • stderr <boolean> Si ceci est défini sur true, alors worker.stderr n'est pas automatiquement acheminé vers process.stderr dans le parent.

    • workerData <any> Toute valeur JavaScript qui est clonée et mise à disposition en tant que require('node:worker_threads').workerData. Le clonage se produit comme décrit dans l'algorithme de clonage structuré HTML , et une erreur est levée si l'objet ne peut pas être cloné (par exemple, parce qu'il contient des function).

    • trackUnmanagedFds <boolean> Si ceci est défini sur true, alors le Worker suit les descripteurs de fichiers bruts gérés via fs.open() et fs.close(), et les ferme lorsque le Worker se termine, de manière similaire aux autres ressources comme les sockets réseau ou les descripteurs de fichiers gérés via l'API FileHandle. Cette option est automatiquement héritée par tous les Worker imbriqués. Par défaut : true.

    • transferList <Object[]> Si un ou plusieurs objets de type MessagePort sont passés dans workerData, une transferList est requise pour ces éléments, sinon ERR_MISSING_MESSAGE_PORT_IN_TRANSFER_LIST est levée. Voir port.postMessage() pour plus d'informations.

    • resourceLimits <Object> Un ensemble facultatif de limites de ressources pour la nouvelle instance de moteur JS. Atteindre ces limites entraîne la terminaison de l'instance Worker. Ces limites n'affectent que le moteur JS, et aucune donnée externe, y compris aucun ArrayBuffer. Même si ces limites sont définies, le processus peut toujours s'arrêter s'il rencontre une situation globale de manque de mémoire.

    • maxOldGenerationSizeMb <number> La taille maximale du tas principal en Mo. Si l'argument de ligne de commande --max-old-space-size est défini, il remplace ce paramètre.

    • maxYoungGenerationSizeMb <number> La taille maximale d'un espace de tas pour les objets récemment créés. Si l'argument de ligne de commande --max-semi-space-size est défini, il remplace ce paramètre.

    • codeRangeSizeMb <number> La taille d'une plage de mémoire pré-allouée utilisée pour le code généré.

    • stackSizeMb <number> La taille de pile maximale par défaut pour le thread. De petites valeurs peuvent conduire à des instances Worker inutilisables. Par défaut : 4.

    • name <string> Un name facultatif à ajouter au titre du worker à des fins de débogage/d'identification, rendant le titre final comme [worker ${id}] ${name}. Par défaut : ''.

Événement : 'error'

Ajouté dans : v10.5.0

L'événement 'error' est émis si le thread worker lève une exception non interceptée. Dans ce cas, le worker est terminé.

Événement : 'exit'

Ajouté dans : v10.5.0

L'événement 'exit' est émis une fois que le worker s'est arrêté. Si le worker a quitté en appelant process.exit(), le paramètre exitCode est le code de sortie passé. Si le worker a été terminé, le paramètre exitCode est 1.

C'est le dernier événement émis par toute instance Worker.

Événement : 'message'

Ajouté dans : v10.5.0

  • value <any> La valeur transmise

L'événement 'message' est émis lorsque le thread worker a invoqué require('node:worker_threads').parentPort.postMessage(). Voir l'événement port.on('message') pour plus de détails.

Tous les messages envoyés depuis le thread worker sont émis avant que l'événement 'exit' ne soit émis sur l'objet Worker.

Événement : 'messageerror'

Ajouté dans : v14.5.0, v12.19.0

L'événement 'messageerror' est émis lorsque la désérialisation d'un message a échoué.

Événement : 'online'

Ajouté dans : v10.5.0

L'événement 'online' est émis lorsque le thread worker a commencé à exécuter du code JavaScript.

worker.getHeapSnapshot([options])

[Historique]

VersionModifications
v19.1.0Prise en charge des options pour configurer l'instantané du tas.
v13.9.0, v12.17.0Ajouté dans : v13.9.0, v12.17.0
  • options <Object>

    • exposeInternals <boolean> Si vrai, expose les éléments internes dans l'instantané du tas. Défaut : false.
    • exposeNumericValues <boolean> Si vrai, expose les valeurs numériques dans des champs artificiels. Défaut : false.
  • Retourne : <Promise> Une promesse pour un flux lisible contenant un instantané du tas V8

Retourne un flux lisible pour un instantané V8 de l'état actuel du Worker. Voir v8.getHeapSnapshot() pour plus de détails.

Si le thread Worker n'est plus en cours d'exécution, ce qui peut se produire avant que l'événement 'exit' ne soit émis, la Promise retournée est rejetée immédiatement avec une erreur ERR_WORKER_NOT_RUNNING.

worker.performance

Ajouté dans : v15.1.0, v14.17.0, v12.22.0

Un objet qui peut être utilisé pour interroger les informations de performance d'une instance de worker. Similaire à perf_hooks.performance.

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

Ajouté dans : v15.1.0, v14.17.0, v12.22.0

  • utilization1 <Objet> Le résultat d'un appel précédent à eventLoopUtilization().
  • utilization2 <Objet> Le résultat d'un appel précédent à eventLoopUtilization() avant utilization1.
  • Retourne : <Objet>

Le même appel que perf_hooks eventLoopUtilization(), sauf que les valeurs de l'instance worker sont retournées.

Une différence est que, contrairement au thread principal, l'amorçage au sein d'un worker est effectué au sein de la boucle d'événements. Ainsi, l'utilisation de la boucle d'événements est immédiatement disponible une fois que le script du worker commence son exécution.

Un temps idle qui n'augmente pas n'indique pas que le worker est bloqué dans l'amorçage. Les exemples suivants montrent comment toute la durée de vie du worker n'accumule jamais de temps idle, mais est toujours capable de traiter des messages.

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)

L'utilisation de la boucle d'événements d'un worker n'est disponible qu'après l'émission de l'événement 'online', et si elle est appelée avant cela, ou après l'événement 'exit', alors toutes les propriétés ont la valeur 0.

worker.postMessage(value[, transferList])

Ajouté dans : v10.5.0

Envoie un message au worker qui est reçu via require('node:worker_threads').parentPort.on('message'). Voir port.postMessage() pour plus de détails.

worker.ref()

Ajouté dans : v10.5.0

Opposé de unref(), appeler ref() sur un worker précédemment unref()ed n'empêche pas le programme de se terminer s'il s'agit de la seule poignée active restante (comportement par défaut). Si le worker est ref()é, appeler ref() à nouveau n'a aucun effet.

worker.resourceLimits

Ajouté dans : v13.2.0, v12.16.0

Fournit l'ensemble des contraintes de ressources du moteur JS pour ce thread Worker. Si l'option resourceLimits a été passée au constructeur Worker, cela correspond à ses valeurs.

Si le worker s'est arrêté, la valeur de retour est un objet vide.

worker.stderr

Ajouté dans : v10.5.0

Il s'agit d'un flux lisible qui contient les données écrites dans process.stderr à l'intérieur du thread worker. Si stderr: true n'a pas été passé au constructeur Worker, les données sont alors envoyées vers le flux process.stderr du thread parent.

worker.stdin

Ajouté dans : v10.5.0

Si stdin: true a été passé au constructeur Worker, il s'agit d'un flux inscriptible. Les données écrites dans ce flux seront disponibles dans le thread worker en tant que process.stdin.

worker.stdout

Ajouté dans : v10.5.0

Il s'agit d'un flux lisible qui contient les données écrites dans process.stdout à l'intérieur du thread worker. Si stdout: true n'a pas été passé au constructeur Worker, les données sont alors envoyées par pipe vers le flux process.stdout du thread parent.

worker.terminate()

[Historique]

VersionModifications
v12.5.0Cette fonction retourne désormais une Promise. Le passage d'une fonction de rappel est obsolète et était inutile jusqu'à cette version, car le Worker était en réalité terminé de manière synchrone. La terminaison est maintenant une opération entièrement asynchrone.
v10.5.0Ajouté dans : v10.5.0

Arrête toute exécution JavaScript dans le thread worker dès que possible. Retourne une Promise pour le code de sortie qui est rempli lorsque l'événement 'exit' est émis.

worker.threadId

Ajouté dans : v10.5.0

Un identifiant entier pour le thread référencé. À l'intérieur du thread worker, il est disponible en tant que require('node:worker_threads').threadId. Cette valeur est unique pour chaque instance Worker au sein d'un seul processus.

worker.unref()

Ajouté dans : v10.5.0

Appeler unref() sur un worker permet au thread de se terminer si c'est le seul handle actif dans le système d'événements. Si le worker est déjà unref(), appeler unref() à nouveau n'a aucun effet.

Remarques

Blocage synchrone de stdio

Les Worker utilisent l'échange de messages via <MessagePort> pour implémenter les interactions avec stdio. Cela signifie que la sortie stdio provenant d'un Worker peut être bloquée par du code synchrone du côté récepteur qui bloque la boucle d'événements Node.js.

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

if (isMainThread) {
  new Worker(new URL(import.meta.url))
  for (let n = 0; n < 1e10; n++) {
    // Boucle pour simuler du travail.
  }
} else {
  // Cette sortie sera bloquée par la boucle for dans le thread principal.
  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++) {
    // Boucle pour simuler du travail.
  }
} else {
  // Cette sortie sera bloquée par la boucle for dans le thread principal.
  console.log('foo')
}

Lancement de threads worker à partir de scripts de préchargement

Soyez prudent lorsque vous lancez des threads worker à partir de scripts de préchargement (scripts chargés et exécutés à l'aide de l'indicateur de ligne de commande -r). À moins que l'option execArgv ne soit explicitement définie, les nouveaux threads Worker héritent automatiquement des indicateurs de ligne de commande du processus en cours d'exécution et préchargeront les mêmes scripts de préchargement que le thread principal. Si le script de préchargement lance inconditionnellement un thread worker, chaque thread généré en engendrera un autre jusqu'à ce que l'application plante.