Skip to content

Threads de Trabalho (Worker threads)

[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');

Workers (threads) são úteis para realizar operações JavaScript intensivas em CPU. Eles não ajudam muito com trabalho intensivo em I/O. As operações assíncronas de I/O 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 de ArrayBuffer ou compartilhando instâncias de 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 excederia seu benefício.

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

As threads de worker 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 da thread de worker, especificamente as opções argv e execArgv.

worker.getEnvironmentData(key)

[Histórico]

VersãoMudanças
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 pode ser usado como uma chave <Map>.
  • Retorna: <any>

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

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 um 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('Inside 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 é lançado. Isso é uma operação nula 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 no lado do envio. Por exemplo, o Node.js marca os ArrayBuffers que ele usa para seu Buffer pool 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 sucesso.
// typedArray2 também está intacto.
console.log(typedArray1);
console.log(typedArray2);

Não existe equivalente a esta API nos 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 nos 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 é lançado. Isso não tem 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 nos navegadores.

worker.moveMessagePortToContext(port, contextifiedSandbox)

Adicionado em: v11.13.0

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

O MessagePort retornado é um objeto no contexto de destino e herda da sua classe global Object. Objetos passados para o ouvinte port.onmessage() também são criados no contexto de destino e herdam da sua classe global Object.

No entanto, o MessagePort criado não herda mais de EventTarget, e apenas port.onmessage() pode ser usado para receber eventos usando-o.

worker.parentPort

Adicionado em: v10.5.0

Se esta thread for um Worker, este é um MessagePort que permite a comunicação com a thread pai. As mensagens enviadas usando parentPort.postMessage() estão disponíveis na thread pai usando worker.on('message'), e as 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 'Hello, world!'.
  });
  worker.postMessage('Hello, world!');
} 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 outro worker, identificado pelo seu ID de thread.

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

Se a thread de destino lançar 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-filho, 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ãoMudanças
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 o payload 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 motor 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.0Adicionado 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 de Worker. Se value for passado como undefined, qualquer valor definido anteriormente para a key será excluído.

A API worker.setEnvironmentData() define o conteúdo de worker.getEnvironmentData() na thread atual e em todas as novas instâncias de 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), está disponível como worker.threadId. Este valor é único para cada instância de Worker dentro de um único processo.

worker.workerData

Adicionado em: v10.5.0

Um valor JavaScript arbitrário que contém um clone dos dados passados para o construtor Worker desta thread.

Os dados são clonados como se estivessem usando postMessage(), de acordo com o algoritmo de clone estruturado 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ãoAlterações
v18.0.0Não é mais experimental.
v15.4.0Adicionado em: v15.4.0

Instâncias de BroadcastChannel permitem a comunicação assíncrona um-para-muitos com todas as outras instâncias de 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('hello from every worker');
  bc.close();
}

new BroadcastChannel(name)

Adicionado em: v15.4.0

  • name <any> O nome do canal ao qual se conectar. Qualquer valor JavaScript que possa 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: <Function> Invocado com um único argumento MessageEvent quando uma mensagem é recebida.

broadcastChannel.onmessageerror

Adicionado em: v15.4.0

  • Tipo: <Function> Invocado 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 termine se for o único manipulador ativo restante (o comportamento padrão). Se a porta for ref()ed, chamar ref() novamente não tem efeito.

broadcastChannel.unref()

Adicionado em: v15.4.0

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

Classe: MessageChannel

Adicionado em: v10.5.0

Instâncias da classe worker.MessageChannel representam um canal de comunicação assíncrono e bidirecional. O MessageChannel não possui métodos próprios. new MessageChannel() produz um objeto com propriedades port1 e port2, que se referem a instâncias vinculadas 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' });
// Imprime: received { foo: 'bar' } do listener `port1.on('message')`

Classe: MessagePort

[Histórico]

VersãoMudanças
v14.7.0Esta classe agora herda de EventTarget em vez de EventEmitter.
v10.5.0Adicionado em: v10.5.0

Instâncias da classe worker.MessagePort representam uma extremidade de um canal de comunicação assíncrono e bidirecional. 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 navegador.

Evento: 'close'

Adicionado em: v10.5.0

O evento 'close' é emitido assim que um dos lados do canal é 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 listeners neste evento recebem um clone do parâmetro value como passado para postMessage() e nenhum argumento adicional.

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 na extremidade receptora. Essas 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

Desativa o envio posterior de mensagens em ambos os lados da conexão. Este método pode ser chamado quando nenhuma comunicação adicional acontecerá sobre esta MessagePort.

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

port.postMessage(value[, transferList])

[Histórico]

VersãoMudanças
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.0Adicionado 'BlockList' à lista de tipos clonáveis.
v15.9.0, v14.18.0Adicionado 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 que é compatível com o HTML structured clone algorithm.

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 é suportada atualmente.

Se value contém instâncias de SharedArrayBuffer, elas são acessíveis de ambos os threads. Eles não podem ser listados em transferList.

value ainda pode conter instâncias de 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 o `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últiplos threads `Worker` que são filhos do mesmo 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 ter efeitos colaterais.

Para obter 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 sobre 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. Deve-se 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 de 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 sempre deve ser clonado e nunca transferido.

Dependendo de como uma instância de 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 de Buffer o possui. Em particular, para Buffers criados a partir do pool interno de Buffer (usando, por exemplo, Buffer.from() ou Buffer.allocUnsafe()), transferi-los não é possível e eles são sempre clonados, o que envia uma cópia de todo o pool de Buffer. Esse comportamento pode vir com maior uso de memória não intencional e possíveis preocupações de segurança.

Consulte Buffer.allocUnsafe() para obter mais detalhes sobre o pool de Buffer.

Os ArrayBuffers para instâncias de Buffer criadas usando Buffer.alloc() ou Buffer.allocUnsafeSlow() podem sempre ser transferidos, mas, ao fazê-lo, todas as outras visualizações existentes desses ArrayBuffers se tornam inutilizáveis.

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

Como a clonagem de objetos usa o algoritmo de clone estruturado HTML, propriedades não enumeráveis, acessadores de propriedade e protótipos de objeto não são preservados. Em particular, objetos Buffer serão lidos como Uint8Arrays simples no 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());

// Prints: { 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'));

// Prints: { }

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 for ref()ed, chamar ref() novamente não terá efeito.

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

port.start()

Adicionado em: v10.5.0

Começa a receber mensagens nesta MessagePort. Ao usar esta porta como um emissor de eventos, isso é chamado automaticamente assim que os listeners 'message' são anexados.

Este método existe para paridade com a API Web MessagePort. No Node.js, ele só é útil para ignorar mensagens quando nenhum listener de evento está presente. O Node.js também diverge no seu tratamento de .onmessage. Definir automaticamente chama .start(), mas remover a definição permite que as mensagens entrem na fila 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 este for o único manipulador ativo no sistema de eventos. Se a porta já estiver unref()ed, chamar unref() novamente não tem efeito.

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

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ão disponíveis 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 node:cluster module, a comunicação bidirecional pode ser alcançada através da passagem de mensagens entre threads. Internamente, um Worker tem um par embutido de MessagePorts que já estão associados um ao outro quando o Worker é criado. Enquanto o objeto MessagePort no lado pai não é diretamente exposto, suas funcionalidades são expostas através de worker.postMessage() e o evento worker.on('message') no objeto Worker para a thread pai.

Para criar canais de mensagens personalizados (o que é incentivado 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 através de um canal pré-existente, como o global.

Consulte 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 através da barreira da 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ãoMudanças
v19.8.0, v18.16.0Adicionado 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 WHATWG URL 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 WHATWG URL 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.0Adicionado 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 WHATWG URL usando o protocolo file: ou data:. Ao usar um data: URL, os dados são interpretados com base no tipo MIME usando o carregador de módulo ECMAScript. Se options.eval for true, este é 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 filha devem compartilhar suas variáveis de ambiente; nesse caso, as alterações no objeto process.env de uma thread afetam também a outra thread. Padrão: process.env.

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

    • execArgv <string[]> Lista de opções CLI do node passadas para o worker. As opções V8 (como --max-old-space-size) e as 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 direcionado para process.stdout no pai.

    • stderr <boolean> Se isso for definido como true, então worker.stderr não é automaticamente direcionado 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, então o Worker rastreia descritores de arquivo brutos gerenciados através de fs.open() e fs.close(), e os fecha quando o Worker sai, semelhante a outros recursos como soquetes de rede ou descritores de arquivo gerenciados através da API FileHandle. Esta opção é automaticamente herdada por todos os Workers aninhados. Padrão: true.

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

    • resourceLimits <Object> Um conjunto opcional de limites de recursos para a nova instância do mecanismo JS. Atingir esses limites leva ao término 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 de linha de comando --max-old-space-size for definido, ele substituirá esta configuração.

    • maxYoungGenerationSizeMb <number> O tamanho máximo de um espaço de heap para objetos criados recentemente. Se o argumento de linha de comando --max-semi-space-size for definido, ele substituirá 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 padrão da pilha para a thread. Valores pequenos podem levar a instâncias 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, o worker é terminado.

Evento: 'exit'

Adicionado em: v10.5.0

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

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

Evento: 'message'

Adicionado em: v10.5.0

  • value <any> O valor transmitido

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

Todas as mensagens enviadas da thread worker são emitidas antes que o [`'exit'` event`](/pt/api/worker_threads#event-exit) seja 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ãoMudanças
v19.1.0Suporte para opções para configurar o heap snapshot.
v13.9.0, v12.17.0Adicionado em: v13.9.0, v12.17.0
  • options <Object>

    • exposeInternals <boolean> Se verdadeiro, expõe os internos no heap snapshot. Padrão: false.
    • exposeNumericValues <boolean> Se verdadeiro, expõe valores numéricos em campos artificiais. Padrão: false.
  • Retorna: <Promise> Uma promise para um Readable Stream contendo um V8 heap snapshot

Retorna um stream legível para um snapshot V8 do estado atual do Worker. Consulte v8.getHeapSnapshot() para obter mais detalhes.

Se a thread Worker não estiver mais em execução, o que pode ocorrer antes que o evento `'exit'` event`](/pt/api/worker_threads#event-exit) seja 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. Semelhante 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 para eventLoopUtilization().
  • utilization2 <Object> O resultado de uma chamada anterior para 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, o bootstrapping dentro de um worker é feito 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 ser executado.

Um tempo idle que não aumenta não indica que o worker está preso no bootstrap. Os exemplos a seguir mostram como toda a vida útil 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' emitido e, se chamado antes disso ou após o evento 'exit' emitido, todas as propriedades têm o valor de 0.

worker.postMessage(value[, transferList])

Adicionado em: v10.5.0

Envia uma mensagem ao worker que é recebida via require('node:worker_threads').parentPort.on('message'). Consulte port.postMessage() para obter 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 handle 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 motor JS para este thread Worker. Se a opção resourceLimits foi passada para o construtor Worker, isso corresponde aos seus valores.

Se o worker parou, o valor de retorno é um objeto vazio.

worker.stderr

Adicionado em: v10.5.0

Este é um stream legível que contém dados gravados em process.stderr dentro do thread worker. Se stderr: true não foi passado para o construtor Worker, então os dados são enviados para o stream process.stderr do 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 gravados neste fluxo estarão disponíveis na thread do worker como process.stdin.

worker.stdout

Adicionado em: v10.5.0

Este é um fluxo legível que contém dados gravados em process.stdout dentro da thread do 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ãoMudanças
v12.5.0Esta função agora retorna uma Promise. Passar um callback está obsoleto e era inútil até esta versão, pois o Worker era realmente terminado de forma síncrona. Terminar agora é uma operação totalmente assíncrona.
v10.5.0Adicionado em: v10.5.0

Interrompe toda a execução de JavaScript na thread do 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 do 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 este for o único identificador ativo no sistema de eventos. Se o worker já estiver unref()ed, chamar unref() novamente não tem efeito.

Notas

Bloqueio Síncrono de stdio

Os Workers utilizam passagem de mensagens através de <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

Tenha cuidado ao iniciar threads worker a partir de scripts de pré-carregamento (scripts carregados e executados usando o sinalizador de linha de comando -r). A menos que a opção execArgv seja explicitamente definida, novas threads Worker herdam automaticamente os sinalizadores 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 irá gerar outra até que o aplicativo falhe.