Skip to content

Threads de trabalhador

[Estável: 2 - Estável]

Estável: 2 Estabilidade: 2 - Estável

Código-fonte: lib/worker_threads.js

O módulo node:worker_threads permite o uso de threads que executam JavaScript em paralelo. Para acessá-lo:

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

Trabalhadores (threads) são úteis para executar operações JavaScript intensivas em CPU. Eles não ajudam muito com trabalho intensivo em E/S. As operações de E/S assíncronas integradas do Node.js são mais eficientes do que os Workers podem ser.

Ao contrário de child_process ou cluster, worker_threads podem compartilhar memória. Eles fazem isso transferindo instâncias ArrayBuffer ou compartilhando instâncias 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))
}

O exemplo acima gera uma thread Worker para cada chamada parseJSAsync(). Na prática, use um pool de Workers para esses tipos de tarefas. Caso contrário, a sobrecarga de criar Workers provavelmente excederá seu benefício.

Ao implementar um pool de trabalhadores, use a API AsyncResource para informar as ferramentas de diagnóstico (por exemplo, para fornecer rastros de pilha assíncronos) sobre a correlação entre tarefas e seus resultados. Veja "Usando AsyncResource para um pool de threads Worker" na documentação async_hooks para um exemplo de implementação.

Threads de trabalhador herdam opções não específicas do processo por padrão. Consulte Opções do construtor Worker para saber como personalizar as opções de thread de trabalhador, especificamente as opções argv e execArgv.

worker.getEnvironmentData(key)

[Histórico]

VersãoAlterações
v17.5.0, v16.15.0Não é mais experimental.
v15.12.0, v14.18.0Adicionado em: v15.12.0, v14.18.0
  • key <any> Qualquer valor JavaScript arbitrário e clonável que possa ser usado como chave de um <Map>.
  • Retorna: <any>

Dentro de uma thread worker, worker.getEnvironmentData() retorna um clone dos dados passados para worker.setEnvironmentData() da thread de geração. Cada novo Worker recebe automaticamente sua própria cópia dos dados do ambiente.

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')) // Imprime 'World!'.
}

worker.isMainThread

Adicionado em: v10.5.0

É true se este código não estiver sendo executado dentro de uma thread Worker.

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

if (isMainThread) {
  // Isso recarrega o arquivo atual dentro de uma instância Worker.
  new Worker(__filename)
} else {
  console.log('Dentro do Worker!')
  console.log(isMainThread) // Imprime 'false'.
}

worker.markAsUntransferable(object)

Adicionado em: v14.5.0, v12.19.0

  • object <any> Qualquer valor JavaScript arbitrário.

Marca um objeto como não transferível. Se object ocorrer na lista de transferência de uma chamada port.postMessage(), um erro será lançado. Esta é uma operação sem efeito se object for um valor primitivo.

Em particular, isso faz sentido para objetos que podem ser clonados, em vez de transferidos, e que são usados por outros objetos do lado do remetente. Por exemplo, o Node.js marca os ArrayBuffers que ele usa para seu pool Buffer com isso.

Esta operação não pode ser desfeita.

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 {
  // Isso lançará um erro, porque pooledBuffer não é transferível.
  port1.postMessage(typedArray1, [typedArray1.buffer])
} catch (error) {
  // error.name === 'DataCloneError'
}

// A linha a seguir imprime o conteúdo de typedArray1 -- ele ainda possui
// sua memória e não foi transferido. Sem
// `markAsUntransferable()`, isso imprimiria um Uint8Array vazio e a
// chamada postMessage teria sido bem-sucedida.
// typedArray2 também está intacto.
console.log(typedArray1)
console.log(typedArray2)

Não existe um equivalente a esta API em navegadores.

worker.isMarkedAsUntransferable(object)

Adicionado em: v21.0.0

Verifica se um objeto está marcado como não transferível com markAsUntransferable().

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

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

isMarkedAsUntransferable(pooledBuffer) // Retorna true.

Não existe equivalente a esta API em navegadores.

worker.markAsUncloneable(object)

Adicionado em: v23.0.0

  • object <any> Qualquer valor JavaScript arbitrário.

Marca um objeto como não clonável. Se object for usado como message em uma chamada port.postMessage(), um erro será lançado. Esta é uma operação sem efeito se object for um valor primitivo.

Isso não tem efeito em ArrayBuffer, ou qualquer objeto semelhante a Buffer.

Esta operação não pode ser desfeita.

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

const anyObject = { foo: 'bar' }
markAsUncloneable(anyObject)
const { port1 } = new MessageChannel()
try {
  // Isso lançará um erro, porque anyObject não é clonável.
  port1.postMessage(anyObject)
} catch (error) {
  // error.name === 'DataCloneError'
}

Não existe equivalente a esta API em navegadores.

worker.moveMessagePortToContext(port, contextifiedSandbox)

Adicionado em: v11.13.0

Transfere uma MessagePort para um contexto vm diferente. O objeto port original é tornado inutilizável, e a instância MessagePort retornada toma seu lugar.

A MessagePort retornada é um objeto no contexto de destino e herda da sua classe global Object. Os objetos passados para o listener port.onmessage() também são criados no contexto de destino e herdam da sua classe global Object.

Entretanto, a MessagePort criada não herda mais de EventTarget, e somente port.onmessage() pode ser usado para receber eventos usando-a.

worker.parentPort

Adicionado em: v10.5.0

Se esta thread for uma Worker, esta é uma MessagePort permitindo comunicação com a thread pai. Mensagens enviadas usando parentPort.postMessage() estão disponíveis na thread pai usando worker.on('message'), e mensagens enviadas da thread pai usando worker.postMessage() estão disponíveis nesta thread usando 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) // Imprime 'Olá, mundo!'.
  })
  worker.postMessage('Olá, mundo!')
} else {
  // Quando uma mensagem da thread pai é recebida, envie-a de volta:
  parentPort.once('message', message => {
    parentPort.postMessage(message)
  })
}

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

Adicionado em: v22.5.0

[Estável: 1 - Experimental]

Estável: 1 Estabilidade: 1.1 - Desenvolvimento ativo

Envia um valor para outra worker, identificada pelo seu ID de thread.

Se a thread de destino não tiver um ouvinte para o evento workerMessage, a operação lançará um erro ERR_WORKER_MESSAGING_FAILED.

Se a thread de destino lançou um erro ao processar o evento workerMessage, a operação lançará um erro ERR_WORKER_MESSAGING_ERRORED.

Este método deve ser usado quando a thread de destino não for o pai ou filho direto da thread atual. Se as duas threads forem pai-filhos, use require('node:worker_threads').parentPort.postMessage() e worker.postMessage() para permitir que as threads se comuniquem.

O exemplo abaixo mostra o uso de postMessageToThread: ele cria 10 threads aninhadas, a última tentará se comunicar com a 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)

[Histórico]

VersãoAlterações
v15.12.0O argumento port agora também pode se referir a um BroadcastChannel.
v12.3.0Adicionado em: v12.3.0

Recebe uma única mensagem de um determinado MessagePort. Se nenhuma mensagem estiver disponível, undefined é retornado; caso contrário, um objeto com uma única propriedade message que contém a carga útil da mensagem, correspondente à mensagem mais antiga na fila do MessagePort.

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

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

Quando esta função é usada, nenhum evento 'message' é emitido e o listener onmessage não é invocado.

worker.resourceLimits

Adicionado em: v13.2.0, v12.16.0

Fornece o conjunto de restrições de recursos do mecanismo JS dentro desta thread Worker. Se a opção resourceLimits foi passada para o construtor Worker, isso corresponde aos seus valores.

Se isso for usado na thread principal, seu valor é um objeto vazio.

worker.SHARE_ENV

Adicionado em: v11.14.0

Um valor especial que pode ser passado como a opção env do construtor Worker, para indicar que a thread atual e a thread Worker devem compartilhar acesso de leitura e escrita ao mesmo conjunto de variáveis de ambiente.

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

worker.setEnvironmentData(key[, value])

[Histórico]

VersãoAlterações
v17.5.0, v16.15.0Não mais experimental.
v15.12.0, v14.18.0Adicionada em: v15.12.0, v14.18.0
  • key <any> Qualquer valor JavaScript arbitrário e clonável que pode ser usado como uma chave <Map>.
  • value <any> Qualquer valor JavaScript arbitrário e clonável que será clonado e passado automaticamente para todas as novas instâncias Worker. Se value for passado como undefined, qualquer valor previamente definido para a key será deletado.

A API worker.setEnvironmentData() define o conteúdo de worker.getEnvironmentData() na thread atual e em todas as novas instâncias Worker geradas a partir do contexto atual.

worker.threadId

Adicionado em: v10.5.0

Um identificador inteiro para a thread atual. No objeto worker correspondente (se houver algum), ele está disponível como worker.threadId. Este valor é único para cada instância Worker dentro de um único processo.

worker.workerData

Adicionado em: v10.5.0

Um valor JavaScript arbitrário que contém uma cópia dos dados passados para o construtor Worker desta thread.

Os dados são clonados como se estivesse usando postMessage(), de acordo com o algoritmo de clonagem estruturada HTML.

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

if (isMainThread) {
  const worker = new Worker(__filename, { workerData: 'Olá, mundo!' })
} else {
  console.log(workerData) // Imprime 'Olá, mundo!'.
}

Classe: BroadcastChannel extends EventTarget

[Histórico]

VersãoMudanças
v18.0.0Não mais experimental.
v15.4.0Adicionada em: v15.4.0

Instâncias de BroadcastChannel permitem comunicação assíncrona de um-para-muitos com todas as outras instâncias BroadcastChannel vinculadas ao mesmo nome 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('Olá de cada worker')
  bc.close()
}

new BroadcastChannel(name)

Adicionado em: v15.4.0

  • name <qualquer> O nome do canal para conectar. Qualquer valor JavaScript que pode ser convertido em uma string usando ${name} é permitido.

broadcastChannel.close()

Adicionado em: v15.4.0

Fecha a conexão BroadcastChannel.

broadcastChannel.onmessage

Adicionado em: v15.4.0

  • Tipo: <Função> Invoca com um único argumento MessageEvent quando uma mensagem é recebida.

broadcastChannel.onmessageerror

Adicionado em: v15.4.0

  • Tipo: <Function> Invoca quando uma mensagem recebida não pode ser desserializada.

broadcastChannel.postMessage(message)

Adicionado em: v15.4.0

  • message <any> Qualquer valor JavaScript clonável.

broadcastChannel.ref()

Adicionado em: v15.4.0

Oposto de unref(). Chamar ref() em um BroadcastChannel previamente unref()ed não permite que o programa saia se for o único manipulador ativo restante (o comportamento padrão). Se a porta estiver ref()ed, chamar ref() novamente não terá efeito.

broadcastChannel.unref()

Adicionado em: v15.4.0

Chamar unref() em um BroadcastChannel permite que a thread saia se este for o único manipulador ativo no sistema de eventos. Se o BroadcastChannel já estiver unref()ed, chamar unref() novamente não terá efeito.

Classe: MessageChannel

Adicionado em: v10.5.0

Instâncias da classe worker.MessageChannel representam um canal de comunicação bidirecional assíncrono. O MessageChannel não possui métodos próprios. new MessageChannel() retorna um objeto com propriedades port1 e port2, que se referem a instâncias MessagePort vinculadas.

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

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

Classe: MessagePort

[Histórico]

VersãoAlterações
v14.7.0Esta classe agora herda de EventTarget em vez de EventEmitter.
v10.5.0Adicionada em: v10.5.0

Instâncias da classe worker.MessagePort representam uma extremidade de um canal de comunicação bidirecional assíncrono. Pode ser usado para transferir dados estruturados, regiões de memória e outros MessagePorts entre diferentes Workers.

Esta implementação corresponde aos MessagePort do navegadors.

Evento: 'close'

Adicionado em: v10.5.0

O evento 'close' é emitido assim que um dos lados do canal for desconectado.

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

// Imprime:
//   foobar
//   closed!
port2.on('message', message => console.log(message))
port2.on('close', () => console.log('closed!'))

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

Evento: 'message'

Adicionado em: v10.5.0

  • value <any> O valor transmitido

O evento 'message' é emitido para qualquer mensagem recebida, contendo a entrada clonada de port.postMessage().

Os ouvintes deste evento recebem um clone do parâmetro value como passado para postMessage() e nenhum outro argumento.

Evento: 'messageerror'

Adicionado em: v14.5.0, v12.19.0

O evento 'messageerror' é emitido quando a desserialização de uma mensagem falha.

Atualmente, este evento é emitido quando ocorre um erro ao instanciar o objeto JS postado no lado receptor. Tais situações são raras, mas podem acontecer, por exemplo, quando certos objetos da API Node.js são recebidos em um vm.Context (onde as APIs Node.js estão atualmente indisponíveis).

port.close()

Adicionado em: v10.5.0

Desabilita o envio posterior de mensagens em qualquer lado da conexão. Este método pode ser chamado quando não houver mais comunicação através desta MessagePort.

O evento 'close' é emitido em ambas as instâncias MessagePort que fazem parte do canal.

port.postMessage(value[, transferList])

[Histórico]

VersãoAlterações
v21.0.0Um erro é lançado quando um objeto não transferível está na lista de transferência.
v15.6.0Adicionado X509Certificate à lista de tipos clonáveis.
v15.0.0Adicionado CryptoKey à lista de tipos clonáveis.
v15.14.0, v14.18.0Adicionar 'BlockList' à lista de tipos clonáveis.
v15.9.0, v14.18.0Adicionar tipos 'Histogram' à lista de tipos clonáveis.
v14.5.0, v12.19.0Adicionado KeyObject à lista de tipos clonáveis.
v14.5.0, v12.19.0Adicionado FileHandle à lista de tipos transferíveis.
v10.5.0Adicionado em: v10.5.0

Envia um valor JavaScript para o lado receptor deste canal. value é transferido de uma forma compatível com o algoritmo de clonagem estruturada HTML.

Em particular, as diferenças significativas para JSON são:

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

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

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

transferList pode ser uma lista de objetos ArrayBuffer, MessagePort e FileHandle. Após a transferência, eles não são mais utilizáveis no lado de envio do canal (mesmo que não estejam contidos em value). Ao contrário dos processos filhos, a transferência de handles como sockets de rede não é atualmente suportada.

Se value contiver instâncias SharedArrayBuffer, elas são acessíveis de qualquer thread. Elas não podem ser listadas em transferList.

value ainda pode conter instâncias ArrayBuffer que não estão em transferList; nesse caso, a memória subjacente é copiada em vez de movida.

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])
// Isso posta uma cópia de `uint8Array`:
port2.postMessage(uint8Array)
// Isso não copia dados, mas torna `uint8Array` inutilizável:
port2.postMessage(uint8Array, [uint8Array.buffer])

// A memória para `sharedUint8Array` é acessível tanto do
// original quanto da cópia recebida por `.on('message')`:
const sharedUint8Array = new Uint8Array(new SharedArrayBuffer(4))
port2.postMessage(sharedUint8Array)

// Isso transfere uma porta de mensagem recém-criada para o receptor.
// Isso pode ser usado, por exemplo, para criar canais de comunicação entre
// múltiplas threads `Worker` que são filhos da mesma thread pai.
const otherChannel = new MessageChannel()
port2.postMessage({ port: otherChannel.port1 }, [otherChannel.port1])

O objeto de mensagem é clonado imediatamente e pode ser modificado após a postagem sem efeitos colaterais.

Para mais informações sobre os mecanismos de serialização e desserialização por trás desta API, consulte a API de serialização do módulo node:v8.

Considerações ao transferir TypedArrays e Buffers

Todas as instâncias de TypedArray e Buffer são visualizações de um ArrayBuffer subjacente. Ou seja, é o ArrayBuffer que realmente armazena os dados brutos, enquanto os objetos TypedArray e Buffer fornecem uma maneira de visualizar e manipular os dados. É possível e comum que várias visualizações sejam criadas sobre a mesma instância de ArrayBuffer. É necessário ter muito cuidado ao usar uma lista de transferência para transferir um ArrayBuffer, pois isso faz com que todas as instâncias de TypedArray e Buffer que compartilham o mesmo ArrayBuffer se tornem inutilizáveis.

js
const ab = new ArrayBuffer(10)

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

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

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

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

Para instâncias Buffer, especificamente, se o ArrayBuffer subjacente pode ser transferido ou clonado depende inteiramente de como as instâncias foram criadas, o que muitas vezes não pode ser determinado de forma confiável.

Um ArrayBuffer pode ser marcado com markAsUntransferable() para indicar que ele deve sempre ser clonado e nunca transferido.

Dependendo de como uma instância Buffer foi criada, ela pode ou não possuir seu ArrayBuffer subjacente. Um ArrayBuffer não deve ser transferido a menos que se saiba que a instância Buffer o possui. Em particular, para Buffers criados a partir do pool interno Buffer (usando, por exemplo, Buffer.from() ou Buffer.allocUnsafe()), transferir eles não é possível e eles são sempre clonados, o que envia uma cópia de todo o pool Buffer. Esse comportamento pode trazer um uso de memória mais alto e preocupações de segurança imprevistas.

Veja Buffer.allocUnsafe() para mais detalhes sobre o pool Buffer.

Os ArrayBuffers para instâncias Buffer criadas usando Buffer.alloc() ou Buffer.allocUnsafeSlow() podem sempre ser transferidos, mas isso torna todas as outras visualizações existentes desses ArrayBuffers inutilizáveis.

Considerações ao clonar objetos com protótipos, classes e acessores

Como a clonagem de objetos usa o algoritmo de clone estruturado HTML, propriedades não enumeráveis, acessores de propriedade e protótipos de objetos não são preservados. Em particular, objetos Buffer serão lidos como Uint8Array simples do lado receptor, e instâncias de classes JavaScript serão clonadas como objetos 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())

// Imprime: { c: 3 }

Essa limitação se estende a muitos objetos embutidos, como o objeto global URL:

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

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

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

// Imprime: { }

port.hasRef()

Adicionado em: v18.1.0, v16.17.0

[Estável: 1 - Experimental]

Estável: 1 Estabilidade: 1 - Experimental

Se verdadeiro, o objeto MessagePort manterá o loop de eventos do Node.js ativo.

port.ref()

Adicionado em: v10.5.0

Oposto de unref(). Chamar ref() em uma porta previamente unref()ed não permite que o programa saia se for o único manipulador ativo restante (o comportamento padrão). Se a porta estiver ref()ed, chamar ref() novamente não tem efeito.

Se os ouvintes forem anexados ou removidos usando .on('message'), a porta é ref()ed e unref()ed automaticamente dependendo se os ouvintes para o evento existem.

port.start()

Adicionado em: v10.5.0

Inicia o recebimento de mensagens neste MessagePort. Ao usar esta porta como um emissor de eventos, isso é chamado automaticamente assim que os ouvintes de 'message' são anexados.

Este método existe para paridade com a API MessagePort da Web. No Node.js, só é útil para ignorar mensagens quando nenhum ouvinte de eventos está presente. O Node.js também diverge em seu tratamento de .onmessage. Definir isso chama automaticamente .start(), mas desdefini-lo permite que as mensagens sejam enfileiradas até que um novo manipulador seja definido ou a porta seja descartada.

port.unref()

Adicionado em: v10.5.0

Chamar unref() em uma porta permite que a thread saia se esta for o único manipulador ativo no sistema de eventos. Se a porta já estiver unref(), chamar unref() novamente não terá efeito.

Se ouvintes forem anexados ou removidos usando .on('message'), a porta é ref() e unref() automaticamente, dependendo se existem ouvintes para o evento.

Classe: Worker

Adicionado em: v10.5.0

A classe Worker representa uma thread de execução JavaScript independente. A maioria das APIs do Node.js está disponível dentro dela.

Diferenças notáveis dentro de um ambiente Worker são:

Criar instâncias Worker dentro de outros Workers é possível.

Como Web Workers e o módulo node:cluster, a comunicação bidirecional pode ser alcançada por meio da passagem de mensagens entre threads. Internamente, um Worker possui um par embutido de MessagePorts que já estão associados um ao outro quando o Worker é criado. Embora o objeto MessagePort do lado pai não seja exposto diretamente, suas funcionalidades são expostas por meio de worker.postMessage() e o evento worker.on('message') no objeto Worker para a thread pai.

Para criar canais de mensagens personalizados (o que é recomendado em vez de usar o canal global padrão porque facilita a separação de preocupações), os usuários podem criar um objeto MessageChannel em qualquer thread e passar um dos MessagePorts nesse MessageChannel para a outra thread por meio de um canal preexistente, como o global.

Veja port.postMessage() para obter mais informações sobre como as mensagens são passadas e que tipo de valores JavaScript podem ser transportados com sucesso pela barreira de thread.

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

[Histórico]

VersãoAlterações
v19.8.0, v18.16.0Adicionou suporte para uma opção name, que permite adicionar um nome ao título do worker para depuração.
v14.9.0O parâmetro filename pode ser um objeto URL WHATWG usando o protocolo data:.
v14.9.0A opção trackUnmanagedFds foi definida como true por padrão.
v14.6.0, v12.19.0A opção trackUnmanagedFds foi introduzida.
v13.13.0, v12.17.0A opção transferList foi introduzida.
v13.12.0, v12.17.0O parâmetro filename pode ser um objeto URL WHATWG usando o protocolo file:.
v13.4.0, v12.16.0A opção argv foi introduzida.
v13.2.0, v12.16.0A opção resourceLimits foi introduzida.
v10.5.0Adicionada em: v10.5.0
  • filename <string> | <URL> O caminho para o script principal ou módulo do Worker. Deve ser um caminho absoluto ou um caminho relativo (ou seja, relativo ao diretório de trabalho atual) começando com ./ ou ../, ou um objeto URL WHATWG usando o protocolo file: ou data:. Ao usar uma URL data:, os dados são interpretados com base no tipo MIME usando o carregador de módulo ECMAScript. Se options.eval for true, esta é uma string contendo código JavaScript em vez de um caminho.

  • options <Object>

    • argv <any[]> Lista de argumentos que seriam convertidos em string e anexados a process.argv no worker. Isso é muito semelhante ao workerData, mas os valores estão disponíveis no process.argv global como se fossem passados como opções de CLI para o script.

    • env <Object> Se definido, especifica o valor inicial de process.env dentro da thread Worker. Como um valor especial, worker.SHARE_ENV pode ser usado para especificar que a thread pai e a thread filho devem compartilhar suas variáveis de ambiente; nesse caso, as alterações no objeto process.env de uma thread afetam a outra thread também. Padrão: process.env.

    • eval <boolean> Se true e o primeiro argumento for uma string, interpreta o primeiro argumento do construtor como um script que é executado assim que o worker estiver online.

    • execArgv <string[]> Lista de opções de CLI do Node passadas para o worker. Opções V8 (como --max-old-space-size) e opções que afetam o processo (como --title) não são suportadas. Se definido, isso é fornecido como process.execArgv dentro do worker. Por padrão, as opções são herdadas da thread pai.

    • stdin <boolean> Se isso for definido como true, então worker.stdin fornece um fluxo gravável cujo conteúdo aparece como process.stdin dentro do Worker. Por padrão, nenhum dado é fornecido.

    • stdout <boolean> Se isso for definido como true, então worker.stdout não é automaticamente canalizado para process.stdout no pai.

    • stderr <boolean> Se isso for definido como true, então worker.stderr não é automaticamente canalizado para process.stderr no pai.

    • workerData <any> Qualquer valor JavaScript que é clonado e disponibilizado como require('node:worker_threads').workerData. A clonagem ocorre como descrito no algoritmo de clonagem estruturada HTML, e um erro é lançado se o objeto não puder ser clonado (por exemplo, porque contém functions).

    • trackUnmanagedFds <boolean> Se isso for definido como true, o Worker rastreia descritores de arquivos brutos gerenciados por meio de fs.open() e fs.close(), e os fecha quando o Worker sair, semelhante a outros recursos como sockets de rede ou descritores de arquivos gerenciados por meio da API FileHandle. Esta opção é herdada automaticamente por todos os Workers aninhados. Padrão: true.

    • transferList <Object[]> Se um ou mais objetos do tipo MessagePort forem passados em workerData, uma transferList é necessária para esses itens ou ERR_MISSING_MESSAGE_PORT_IN_TRANSFER_LIST é lançado. Veja port.postMessage() para mais informações.

    • resourceLimits <Object> Um conjunto opcional de limites de recursos para a nova instância do mecanismo JS. Alcançar esses limites leva ao encerramento da instância Worker. Esses limites afetam apenas o mecanismo JS e nenhum dado externo, incluindo nenhum ArrayBuffer. Mesmo que esses limites sejam definidos, o processo ainda pode ser abortado se encontrar uma situação global de falta de memória.

    • maxOldGenerationSizeMb <number> O tamanho máximo do heap principal em MB. Se o argumento da linha de comando --max-old-space-size estiver definido, ele substitui esta configuração.

    • maxYoungGenerationSizeMb <number> O tamanho máximo de um espaço de heap para objetos criados recentemente. Se o argumento da linha de comando --max-semi-space-size estiver definido, ele substitui esta configuração.

    • codeRangeSizeMb <number> O tamanho de um intervalo de memória pré-alocado usado para código gerado.

    • stackSizeMb <number> O tamanho máximo de pilha padrão para a thread. Valores pequenos podem levar a instâncias de Worker inutilizáveis. Padrão: 4.

    • name <string> Um name opcional a ser anexado ao título do worker para fins de depuração/identificação, tornando o título final como [worker ${id}] ${name}. Padrão: ''.

Evento: 'error'

Adicionado em: v10.5.0

O evento 'error' é emitido se a thread worker lançar uma exceção não capturada. Nesse caso, a worker é encerrada.

Evento: 'exit'

Adicionado em: v10.5.0

O evento 'exit' é emitido assim que a worker para. Se a worker foi encerrada chamando process.exit(), o parâmetro exitCode é o código de saída passado. Se a worker foi encerrada, o parâmetro exitCode é 1.

Este é o evento final emitido por qualquer instância Worker.

Evento: 'message'

Adicionado em: v10.5.0

O evento 'message' é emitido quando a thread worker invocou require('node:worker_threads').parentPort.postMessage(). Veja o evento port.on('message') para mais detalhes.

Todas as mensagens enviadas da thread worker são emitidas antes do evento 'exit' ser emitido no objeto Worker.

Evento: 'messageerror'

Adicionado em: v14.5.0, v12.19.0

O evento 'messageerror' é emitido quando a desserialização de uma mensagem falha.

Evento: 'online'

Adicionado em: v10.5.0

O evento 'online' é emitido quando a thread worker começou a executar o código JavaScript.

worker.getHeapSnapshot([options])

[Histórico]

VersãoAlterações
v19.1.0Suporte a opções para configurar o snapshot do heap.
v13.9.0, v12.17.0Adicionada em: v13.9.0, v12.17.0
  • options <Objeto>

    • exposeInternals <booleano> Se verdadeiro, expõe elementos internos no snapshot do heap. Padrão: false.
    • exposeNumericValues <booleano> Se verdadeiro, expõe valores numéricos em campos artificiais. Padrão: false.
  • Retorna: <Promise> Uma promise para um fluxo legível contendo um snapshot do heap V8

Retorna um fluxo legível para um snapshot V8 do estado atual da Worker. Veja v8.getHeapSnapshot() para mais detalhes.

Se a thread Worker não estiver mais em execução, o que pode ocorrer antes do evento 'exit' ser emitido, a Promise retornada é rejeitada imediatamente com um erro ERR_WORKER_NOT_RUNNING.

worker.performance

Adicionado em: v15.1.0, v14.17.0, v12.22.0

Um objeto que pode ser usado para consultar informações de desempenho de uma instância de worker. Similar a perf_hooks.performance.

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

Adicionado em: v15.1.0, v14.17.0, v12.22.0

  • utilization1 <Object> O resultado de uma chamada anterior a eventLoopUtilization().
  • utilization2 <Object> O resultado de uma chamada anterior a eventLoopUtilization() antes de utilization1.
  • Retorna: <Object>

A mesma chamada que perf_hooks eventLoopUtilization(), exceto que os valores da instância do worker são retornados.

Uma diferença é que, ao contrário da thread principal, a inicialização dentro de um worker é feita dentro do loop de eventos. Portanto, a utilização do loop de eventos está imediatamente disponível assim que o script do worker começa a execução.

Um tempo idle que não aumenta não indica que o worker está preso na inicialização. Os exemplos a seguir mostram como a vida útil inteira do worker nunca acumula nenhum tempo idle, mas ainda é capaz de processar mensagens.

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)

A utilização do loop de eventos de um worker está disponível somente após o evento 'online' ser emitido, e se chamado antes disso, ou após o evento 'exit', então todas as propriedades terão o valor 0.

worker.postMessage(value[, transferList])

Adicionado em: v10.5.0

Envia uma mensagem para o worker que é recebida via require('node:worker_threads').parentPort.on('message'). Veja port.postMessage() para mais detalhes.

worker.ref()

Adicionado em: v10.5.0

O oposto de unref(), chamar ref() em um worker previamente unref()ed não permite que o programa saia se for o único manipulador ativo restante (o comportamento padrão). Se o worker for ref()ed, chamar ref() novamente não tem efeito.

worker.resourceLimits

Adicionado em: v13.2.0, v12.16.0

Fornece o conjunto de restrições de recursos do mecanismo JS para esta thread Worker. Se a opção resourceLimits foi passada para o construtor Worker, isto corresponde aos seus valores.

Se o worker parou, o valor retornado é um objeto vazio.

worker.stderr

Adicionado em: v10.5.0

Este é um fluxo legível que contém dados escritos para process.stderr dentro da thread worker. Se stderr: true não foi passado para o construtor Worker, então os dados são canalizados para o fluxo process.stderr da thread pai.

worker.stdin

Adicionado em: v10.5.0

Se stdin: true foi passado para o construtor Worker, este é um fluxo gravável. Os dados escritos neste fluxo ficarão disponíveis na thread worker como process.stdin.

worker.stdout

Adicionado em: v10.5.0

Este é um fluxo legível que contém dados escritos para process.stdout dentro da thread worker. Se stdout: true não foi passado para o construtor Worker, então os dados são canalizados para o fluxo process.stdout da thread pai.

worker.terminate()

[Histórico]

VersãoAlterações
v12.5.0Esta função agora retorna uma Promise. Passar um callback está depreciado e era inútil até esta versão, pois o Worker era realmente terminado sincronicamente. A terminação agora é uma operação totalmente assíncrona.
v10.5.0Adicionada em: v10.5.0

Pare toda a execução JavaScript na thread worker o mais rápido possível. Retorna uma Promise para o código de saída que é cumprida quando o evento 'exit' é emitido.

worker.threadId

Adicionado em: v10.5.0

Um identificador inteiro para a thread referenciada. Dentro da thread worker, está disponível como require('node:worker_threads').threadId. Este valor é único para cada instância Worker dentro de um único processo.

worker.unref()

Adicionado em: v10.5.0

Chamar unref() em um worker permite que a thread saia se esta for a única alça ativa no sistema de eventos. Se o worker já estiver unref()ed, chamar unref() novamente não terá efeito.

Notas

Bloqueio síncrono de stdio

Workers utilizam passagem de mensagens via <MessagePort> para implementar interações com stdio. Isso significa que a saída stdio originada de um Worker pode ser bloqueada por código síncrono na extremidade receptora que está bloqueando o loop de eventos do 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++) {
    // Looping to simulate work.
  }
} else {
  // This output will be blocked by the for loop in the main thread.
  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++) {
    // Looping to simulate work.
  }
} else {
  // This output will be blocked by the for loop in the main thread.
  console.log('foo')
}

Iniciando threads worker a partir de scripts de pré-carregamento

Tome cuidado ao iniciar threads worker a partir de scripts de pré-carregamento (scripts carregados e executados usando a flag de linha de comando -r). A menos que a opção execArgv seja definida explicitamente, novas threads Worker herdam automaticamente as flags de linha de comando do processo em execução e pré-carregarão os mesmos scripts de pré-carregamento que a thread principal. Se o script de pré-carregamento iniciar incondicionalmente uma thread worker, cada thread gerada gerará outra até que o aplicativo trave.