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:
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.
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ão | Mudanças |
|---|---|
| v17.5.0, v16.15.0 | Não é mais experimental. |
| v15.12.0, v14.18.0 | Adicionado 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.
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.
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.
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().
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.
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
port<MessagePort> A porta de mensagem a ser transferida.contextifiedSandbox<Object> Um objeto contextificado conforme retornado pelo métodovm.createContext().- Retorna: <MessagePort>
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').
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
threadId<number> O ID da thread de destino. Se o ID da thread for inválido, um erroERR_WORKER_MESSAGING_FAILEDserá lançado. Se o ID da thread de destino for o ID da thread atual, um erroERR_WORKER_MESSAGING_SAME_THREADserá lançado.value<any> O valor a ser enviado.transferList<Object[]> Se um ou mais objetos do tipoMessagePortforem passados emvalue, umatransferListé necessária para esses itens ouERR_MISSING_MESSAGE_PORT_IN_TRANSFER_LISTé lançado. Consulteport.postMessage()para obter mais informações.timeout<number> Tempo para esperar que a mensagem seja entregue em milissegundos. Por padrão, éundefined, o que significa esperar para sempre. Se a operação atingir o tempo limite, um erroERR_WORKER_MESSAGING_TIMEOUTserá lançado.- Retorna: <Promise> Uma promessa que é cumprida se a mensagem foi processada com sucesso pela thread de destino.
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.
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;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ão | Mudanças |
|---|---|
| v15.12.0 | O argumento port agora também pode se referir a um BroadcastChannel. |
| v12.3.0 | Adicionado em: v12.3.0 |
port<MessagePort> | <BroadcastChannel>- Retorna: <Object> | <undefined>
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.
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: undefinedQuando 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.
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ão | Alterações |
|---|---|
| v17.5.0, v16.15.0 | Não é mais experimental. |
| v15.12.0, v14.18.0 | Adicionado 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 deWorker. Sevaluefor passado comoundefined, qualquer valor definido anteriormente para akeyserá 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.
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ão | Alterações |
|---|---|
| v18.0.0 | Não é mais experimental. |
| v15.4.0 | Adicionado 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.
'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
MessageEventquando 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.
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ão | Mudanças |
|---|---|
| v14.7.0 | Esta classe agora herda de EventTarget em vez de EventEmitter. |
| v10.5.0 | Adicionado em: v10.5.0 |
- Estende: <EventTarget>
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.
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
error<Error> Um objeto Error
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ão | Mudanças |
|---|---|
| v21.0.0 | Um erro é lançado quando um objeto não transferível está na lista de transferência. |
| v15.6.0 | Adicionado X509Certificate à lista de tipos clonáveis. |
| v15.0.0 | Adicionado CryptoKey à lista de tipos clonáveis. |
| v15.14.0, v14.18.0 | Adicionado 'BlockList' à lista de tipos clonáveis. |
| v15.9.0, v14.18.0 | Adicionado tipos 'Histogram' à lista de tipos clonáveis. |
| v14.5.0, v12.19.0 | Adicionado KeyObject à lista de tipos clonáveis. |
| v14.5.0, v12.19.0 | Adicionado FileHandle à lista de tipos transferíveis. |
| v10.5.0 | Adicionado em: v10.5.0 |
value<any>transferList<Object[]>
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:
valuepode conter referências circulares.valuepode conter instâncias de tipos JS embutidos, comoRegExps,BigInts,Maps,Sets, etc.valuepode conter matrizes tipadas, usandoArrayBuffers eSharedArrayBuffers.valuepode conter instâncias deWebAssembly.Module.valuenão pode conter objetos nativos (com suporte em C++) além de:
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.
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.
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 0Para 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.
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:
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
- Retorna: <boolean>
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
- Estende: <EventEmitter>
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:
- Os streams
process.stdin,process.stdouteprocess.stderrpodem ser redirecionados pela thread pai. - A propriedade
require('node:worker_threads').isMainThreadé definida comofalse. - A porta de mensagens
require('node:worker_threads').parentPortestá disponível. process.exit()não interrompe todo o programa, apenas a thread única, eprocess.abort()não está disponível.process.chdir()e os métodosprocessque definem ids de grupo ou usuário não estão disponíveis.process.envé uma cópia das variáveis de ambiente da thread pai, a menos que especificado de outra forma. As alterações em uma cópia não são visíveis em outras threads e não são visíveis para complementos nativos (a menos queworker.SHARE_ENVseja passado como a opçãoenvpara o construtorWorker). No Windows, ao contrário da thread principal, uma cópia das variáveis de ambiente opera de forma sensível a maiúsculas e minúsculas.process.titlenão pode ser modificado.- Os sinais não são entregues através de
process.on('...'). - A execução pode parar em qualquer ponto como resultado de
worker.terminate()ser invocado. - Canais IPC de processos pai não são acessíveis.
- O módulo
trace_eventsnão é suportado. - Complementos nativos só podem ser carregados de várias threads se cumprirem certas condições.
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.
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ão | Mudanças |
|---|---|
| v19.8.0, v18.16.0 | Adicionado suporte para uma opção name, que permite adicionar um nome ao título do worker para depuração. |
| v14.9.0 | O parâmetro filename pode ser um objeto WHATWG URL usando o protocolo data:. |
| v14.9.0 | A opção trackUnmanagedFds foi definida como true por padrão. |
| v14.6.0, v12.19.0 | A opção trackUnmanagedFds foi introduzida. |
| v13.13.0, v12.17.0 | A opção transferList foi introduzida. |
| v13.12.0, v12.17.0 | O parâmetro filename pode ser um objeto WHATWG URL usando o protocolo file:. |
| v13.4.0, v12.16.0 | A opção argv foi introduzida. |
| v13.2.0, v12.16.0 | A opção resourceLimits foi introduzida. |
| v10.5.0 | Adicionado 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 WHATWGURLusando o protocolofile:oudata:. Ao usar umdata:URL, os dados são interpretados com base no tipo MIME usando o carregador de módulo ECMAScript. Seoptions.evalfortrue, 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 aprocess.argvno worker. Isso é muito semelhante aoworkerData, mas os valores estão disponíveis noprocess.argvglobal como se fossem passados como opções de CLI para o script.env<Object> Se definido, especifica o valor inicial deprocess.envdentro da thread Worker. Como um valor especial,worker.SHARE_ENVpode 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 objetoprocess.envde uma thread afetam também a outra thread. Padrão:process.env.eval<boolean> Setruee o primeiro argumento for umastring, 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 comoprocess.execArgvdentro do worker. Por padrão, as opções são herdadas da thread pai.stdin<boolean> Se isso for definido comotrue, entãoworker.stdinfornece um fluxo gravável cujo conteúdo aparece comoprocess.stdindentro do Worker. Por padrão, nenhum dado é fornecido.stdout<boolean> Se isso for definido comotrue, entãoworker.stdoutnão é automaticamente direcionado paraprocess.stdoutno pai.stderr<boolean> Se isso for definido comotrue, entãoworker.stderrnão é automaticamente direcionado paraprocess.stderrno pai.workerData<any> Qualquer valor JavaScript que é clonado e disponibilizado comorequire('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émfunctions).trackUnmanagedFds<boolean> Se isso for definido comotrue, então o Worker rastreia descritores de arquivo brutos gerenciados através defs.open()efs.close(), e os fecha quando o Worker sai, semelhante a outros recursos como soquetes de rede ou descritores de arquivo gerenciados através da APIFileHandle. Esta opção é automaticamente herdada por todos osWorkers aninhados. Padrão:true.transferList<Object[]> Se um ou mais objetos semelhantes aMessagePortforem passados emworkerData, umatransferListé necessária para esses itens ouERR_MISSING_MESSAGE_PORT_IN_TRANSFER_LISTé lançado. Consulteport.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ânciaWorker. Esses limites afetam apenas o mecanismo JS e nenhum dado externo, incluindo nenhumArrayBuffer. 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-sizefor 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-sizefor 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> Umnameopcional 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
err<Error>
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
exitCode<integer>
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/nodejs/api/worker_threads#event-exit) seja emitido no objeto `Worker`.
Evento: 'messageerror'
Adicionado em: v14.5.0, v12.19.0
error<Error> Um objeto Error
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ão | Mudanças |
|---|---|
| v19.1.0 | Suporte para opções para configurar o heap snapshot. |
| v13.9.0, v12.17.0 | Adicionado em: v13.9.0, v12.17.0 |
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/nodejs/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 paraeventLoopUtilization().utilization2<Object> O resultado de uma chamada anterior paraeventLoopUtilization()antes deutilization1.- 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.
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
value<any>transferList<Object[]>
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ão | Mudanças |
|---|---|
| v12.5.0 | Esta 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.0 | Adicionado em: v10.5.0 |
- Retorna: <Promise>
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.
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');
}'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.