Skip to content

V8

Código-fonte: lib/v8.js

O módulo node:v8 expõe APIs específicas da versão do V8 integrado ao binário do Node.js. Ele pode ser acessado usando:

js
const v8 = require('node:v8');

v8.cachedDataVersionTag()

Adicionado em: v8.0.0

Retorna um inteiro representando uma tag de versão derivada da versão do V8, flags de linha de comando e recursos de CPU detectados. Isso é útil para determinar se um buffer cachedData de vm.Script é compatível com esta instância do V8.

js
console.log(v8.cachedDataVersionTag()); // 3947234607
// O valor retornado por v8.cachedDataVersionTag() é derivado da versão do V8,
// flags de linha de comando e recursos de CPU detectados. Teste se o valor
// realmente atualiza quando as flags são alternadas.
v8.setFlagsFromString('--allow_natives_syntax');
console.log(v8.cachedDataVersionTag()); // 183726201

v8.getHeapCodeStatistics()

Adicionado em: v12.8.0

Obtenha estatísticas sobre o código e seus metadados no heap, consulte a API V8 GetHeapCodeAndMetadataStatistics. Retorna um objeto com as seguintes propriedades:

js
{
  code_and_metadata_size: 212208,
  bytecode_and_metadata_size: 161368,
  external_script_source_size: 1410794,
  cpu_profiler_metadata_size: 0,
}

v8.getHeapSnapshot([options])

[Histórico]

VersãoMudanças
v19.1.0Suporte para opções para configurar o heap snapshot.
v11.13.0Adicionado em: v11.13.0
  • options <Objeto>

    • exposeInternals <booleano> Se verdadeiro, expõe internals no heap snapshot. Padrão: false.
    • exposeNumericValues <booleano> Se verdadeiro, expõe valores numéricos em campos artificiais. Padrão: false.
  • Retorna: <stream.Readable> Um Readable contendo o heap snapshot V8.

Gera um snapshot do heap V8 atual e retorna um Readable Stream que pode ser usado para ler a representação serializada em JSON. Este formato de fluxo JSON destina-se a ser usado com ferramentas como o Chrome DevTools. O esquema JSON não está documentado e é específico do mecanismo V8. Portanto, o esquema pode mudar de uma versão do V8 para outra.

Criar um heap snapshot requer memória cerca de duas vezes o tamanho do heap no momento em que o snapshot é criado. Isso resulta no risco de os eliminadores de OOM encerrarem o processo.

Gerar um snapshot é uma operação síncrona que bloqueia o loop de eventos por uma duração dependendo do tamanho do heap.

js
// Imprime o heap snapshot no console
const v8 = require('node:v8');
const stream = v8.getHeapSnapshot();
stream.pipe(process.stdout);

v8.getHeapSpaceStatistics()

[Histórico]

VersãoMudanças
v7.5.0Suporte para valores que excedem o intervalo de inteiros não assinados de 32 bits.
v6.0.0Adicionado em: v6.0.0

Retorna estatísticas sobre os espaços de heap V8, ou seja, os segmentos que compõem o heap V8. Nem a ordenação dos espaços de heap, nem a disponibilidade de um espaço de heap podem ser garantidas, pois as estatísticas são fornecidas por meio da função GetHeapSpaceStatistics do V8 e podem mudar de uma versão do V8 para outra.

O valor retornado é um array de objetos contendo as seguintes propriedades:

json
[
  {
    "space_name": "new_space",
    "space_size": 2063872,
    "space_used_size": 951112,
    "space_available_size": 80824,
    "physical_space_size": 2063872
  },
  {
    "space_name": "old_space",
    "space_size": 3090560,
    "space_used_size": 2493792,
    "space_available_size": 0,
    "physical_space_size": 3090560
  },
  {
    "space_name": "code_space",
    "space_size": 1260160,
    "space_used_size": 644256,
    "space_available_size": 960,
    "physical_space_size": 1260160
  },
  {
    "space_name": "map_space",
    "space_size": 1094160,
    "space_used_size": 201608,
    "space_available_size": 0,
    "physical_space_size": 1094160
  },
  {
    "space_name": "large_object_space",
    "space_size": 0,
    "space_used_size": 0,
    "space_available_size": 1490980608,
    "physical_space_size": 0
  }
]

v8.getHeapStatistics()

[Histórico]

VersãoMudanças
v7.5.0Suporta valores que excedem o intervalo de inteiros não assinados de 32 bits.
v7.2.0Adicionado malloced_memory, peak_malloced_memory e does_zap_garbage.
v1.0.0Adicionado em: v1.0.0

Retorna um objeto com as seguintes propriedades:

total_heap_size O valor de total_heap_size é o número de bytes que o V8 alocou para o heap. Isso pode crescer se used_heap precisar de mais memória.

total_heap_size_executable O valor de total_heap_size_executable é a porção do heap que pode conter código executável, em bytes. Isso inclui a memória usada pelo código compilado por JIT e qualquer memória que deva ser mantida executável.

total_physical_size O valor de total_physical_size é a memória física real usada pelo heap V8, em bytes. Esta é a quantidade de memória que é comprometida (ou em uso) em vez de reservada.

total_available_size O valor de total_available_size é o número de bytes de memória disponíveis para o heap V8. Este valor representa quanta memória adicional o V8 pode usar antes de exceder o limite do heap.

used_heap_size O valor de used_heap_size é o número de bytes atualmente em uso pelos objetos JavaScript do V8. Esta é a memória real em uso e não inclui a memória que foi alocada, mas ainda não foi usada.

heap_size_limit O valor de heap_size_limit é o tamanho máximo do heap V8, em bytes (seja o limite padrão, determinado pelos recursos do sistema, ou o valor passado para a opção --max_old_space_size).

malloced_memory O valor de malloced_memory é o número de bytes alocados através de malloc pelo V8.

peak_malloced_memory O valor de peak_malloced_memory é o número máximo de bytes alocados através de malloc pelo V8 durante o tempo de vida do processo.

does_zap_garbage é um booleano 0/1, que indica se a opção --zap_code_space está habilitada ou não. Isso faz com que o V8 sobrescreva o lixo do heap com um padrão de bits. A pegada RSS (resident set size) fica maior porque toca continuamente em todas as páginas do heap e isso torna menos provável que sejam trocadas pelo sistema operacional.

number_of_native_contexts O valor de native_context é o número de contextos de nível superior atualmente ativos. O aumento desse número ao longo do tempo indica um vazamento de memória.

number_of_detached_contexts O valor de detached_context é o número de contextos que foram desanexados e ainda não foram coletados como lixo. Esse número diferente de zero indica um potencial vazamento de memória.

total_global_handles_size O valor de total_global_handles_size é o tamanho total da memória dos manipuladores globais V8.

used_global_handles_size O valor de used_global_handles_size é o tamanho da memória usada dos manipuladores globais V8.

external_memory O valor de external_memory é o tamanho da memória dos buffers de array e strings externas.

js
{
  total_heap_size: 7326976,
  total_heap_size_executable: 4194304,
  total_physical_size: 7326976,
  total_available_size: 1152656,
  used_heap_size: 3476208,
  heap_size_limit: 1535115264,
  malloced_memory: 16384,
  peak_malloced_memory: 1127496,
  does_zap_garbage: 0,
  number_of_native_contexts: 1,
  number_of_detached_contexts: 0,
  total_global_handles_size: 8192,
  used_global_handles_size: 3296,
  external_memory: 318824
}

v8.queryObjects(ctor[, options])

Adicionado em: v22.0.0, v20.13.0

[Estável: 1 - Experimental]

Estável: 1 Estabilidade: 1 - Desenvolvimento ativo

  • ctor <Function> O construtor que pode ser usado para pesquisar na cadeia de protótipos para filtrar objetos de destino no heap.

  • options <undefined> | <Object>

    • format <string> Se for 'count', a contagem de objetos correspondentes é retornada. Se for 'summary', um array com strings de resumo dos objetos correspondentes é retornado.
  • Retorna: {number|Array

Isso é semelhante à queryObjects() console API fornecida pelo console do Chromium DevTools. Ele pode ser usado para pesquisar objetos que têm o construtor correspondente em sua cadeia de protótipos no heap após uma coleta de lixo completa, o que pode ser útil para testes de regressão de vazamento de memória. Para evitar resultados surpreendentes, os usuários devem evitar usar esta API em construtores cuja implementação eles não controlam ou em construtores que podem ser invocados por outras partes no aplicativo.

Para evitar vazamentos acidentais, esta API não retorna referências brutas aos objetos encontrados. Por padrão, ele retorna a contagem dos objetos encontrados. Se options.format for 'summary', ele retorna um array contendo representações de string breves para cada objeto. A visibilidade fornecida nesta API é semelhante ao que o snapshot do heap fornece, enquanto os usuários podem economizar o custo de serialização e análise e filtrar diretamente os objetos de destino durante a pesquisa.

Apenas objetos criados no contexto de execução atual são incluídos nos resultados.

js
const { queryObjects } = require('node:v8');
class A { foo = 'bar'; }
console.log(queryObjects(A)); // 0
const a = new A();
console.log(queryObjects(A)); // 1
// [ "A { foo: 'bar' }" ]
console.log(queryObjects(A, { format: 'summary' }));

class B extends A { bar = 'qux'; }
const b = new B();
console.log(queryObjects(B)); // 1
// [ "B { foo: 'bar', bar: 'qux' }" ]
console.log(queryObjects(B, { format: 'summary' }));

// Note that, when there are child classes inheriting from a constructor,
// the constructor also shows up in the prototype chain of the child
// classes's prototype, so the child classes's prototype would also be
// included in the result.
console.log(queryObjects(A));  // 3
// [ "B { foo: 'bar', bar: 'qux' }", 'A {}', "A { foo: 'bar' }" ]
console.log(queryObjects(A, { format: 'summary' }));
js
import { queryObjects } from 'node:v8';
class A { foo = 'bar'; }
console.log(queryObjects(A)); // 0
const a = new A();
console.log(queryObjects(A)); // 1
// [ "A { foo: 'bar' }" ]
console.log(queryObjects(A, { format: 'summary' }));

class B extends A { bar = 'qux'; }
const b = new B();
console.log(queryObjects(B)); // 1
// [ "B { foo: 'bar', bar: 'qux' }" ]
console.log(queryObjects(B, { format: 'summary' }));

// Note that, when there are child classes inheriting from a constructor,
// the constructor also shows up in the prototype chain of the child
// classes's prototype, so the child classes's prototype would also be
// included in the result.
console.log(queryObjects(A));  // 3
// [ "B { foo: 'bar', bar: 'qux' }", 'A {}', "A { foo: 'bar' }" ]
console.log(queryObjects(A, { format: 'summary' }));

v8.setFlagsFromString(flags)

Adicionado em: v1.0.0

O método v8.setFlagsFromString() pode ser usado para definir programaticamente as flags de linha de comando do V8. Este método deve ser usado com cuidado. Alterar as configurações depois que a VM for iniciada pode resultar em comportamento imprevisível, incluindo falhas e perda de dados; ou pode simplesmente não fazer nada.

As opções do V8 disponíveis para uma versão do Node.js podem ser determinadas executando node --v8-options.

Uso:

js
// Imprime eventos de GC para stdout por um minuto.
const v8 = require('node:v8');
v8.setFlagsFromString('--trace_gc');
setTimeout(() => { v8.setFlagsFromString('--notrace_gc'); }, 60e3);

v8.stopCoverage()

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

O método v8.stopCoverage() permite que o usuário pare a coleta de cobertura iniciada por NODE_V8_COVERAGE, para que o V8 possa liberar os registros de contagem de execução e otimizar o código. Isso pode ser usado em conjunto com v8.takeCoverage() se o usuário quiser coletar a cobertura sob demanda.

v8.takeCoverage()

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

O método v8.takeCoverage() permite que o usuário grave a cobertura iniciada por NODE_V8_COVERAGE em disco sob demanda. Este método pode ser invocado várias vezes durante a vida útil do processo. Cada vez que o contador de execução será reiniciado e um novo relatório de cobertura será gravado no diretório especificado por NODE_V8_COVERAGE.

Quando o processo está prestes a sair, uma última cobertura ainda será gravada em disco, a menos que v8.stopCoverage() seja invocado antes que o processo seja encerrado.

v8.writeHeapSnapshot([filename[,options]])

[Histórico]

VersãoMudanças
v19.1.0Suporta opções para configurar o snapshot de heap.
v18.0.0Uma exceção agora será lançada se o arquivo não puder ser gravado.
v18.0.0Torna os códigos de erro retornados consistentes em todas as plataformas.
v11.13.0Adicionado em: v11.13.0
  • filename <string> O caminho do arquivo onde o snapshot do heap do V8 deve ser salvo. Se não for especificado, um nome de arquivo com o padrão 'Heap-${yyyymmdd}-${hhmmss}-${pid}-${thread_id}.heapsnapshot' será gerado, onde {pid} será o PID do processo Node.js, {thread_id} será 0 quando writeHeapSnapshot() for chamado do thread principal do Node.js ou o id de um thread de worker.

  • options <Object>

    • exposeInternals <boolean> Se verdadeiro, expõe internos no snapshot de heap. Padrão: false.
    • exposeNumericValues <boolean> Se verdadeiro, expõe valores numéricos em campos artificiais. Padrão: false.
  • Retorna: <string> O nome do arquivo onde o snapshot foi salvo.

Gera um snapshot do heap V8 atual e o grava em um arquivo JSON. Este arquivo destina-se a ser usado com ferramentas como o Chrome DevTools. O esquema JSON não é documentado e específico do motor V8, e pode mudar de uma versão do V8 para a seguinte.

Um snapshot de heap é específico para um único isolado V8. Ao usar worker threads, um snapshot de heap gerado a partir do thread principal não conterá nenhuma informação sobre os workers, e vice-versa.

Criar um snapshot de heap requer memória cerca de duas vezes o tamanho do heap no momento em que o snapshot é criado. Isso resulta no risco de os killers OOM terminarem o processo.

Gerar um snapshot é uma operação síncrona que bloqueia o loop de eventos por uma duração dependendo do tamanho do heap.

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

if (isMainThread) {
  const worker = new Worker(__filename);

  worker.once('message', (filename) => {
    console.log(`worker heapdump: ${filename}`);
    // Agora obtenha um heapdump para o thread principal.
    console.log(`main thread heapdump: ${writeHeapSnapshot()}`);
  });

  // Diga ao worker para criar um heapdump.
  worker.postMessage('heapdump');
} else {
  parentPort.once('message', (message) => {
    if (message === 'heapdump') {
      // Gere um heapdump para o worker
      // e retorne o nome do arquivo para o pai.
      parentPort.postMessage(writeHeapSnapshot());
    }
  });
}

v8.setHeapSnapshotNearHeapLimit(limit)

Adicionado em: v18.10.0, v16.18.0

[Estável: 1 - Experimental]

Estável: 1 Estabilidade: 1 - Experimental

A API não faz nada se --heapsnapshot-near-heap-limit já estiver definido na linha de comando ou se a API for chamada mais de uma vez. limit deve ser um inteiro positivo. Consulte --heapsnapshot-near-heap-limit para obter mais informações.

API de Serialização

A API de serialização fornece meios de serializar valores JavaScript de uma forma que seja compatível com o algoritmo de clone estruturado HTML.

O formato é compatível com versões anteriores (ou seja, seguro para armazenar em disco). Valores JavaScript iguais podem resultar em saídas serializadas diferentes.

v8.serialize(value)

Adicionado em: v8.0.0

Usa um DefaultSerializer para serializar value em um buffer.

ERR_BUFFER_TOO_LARGE será lançado ao tentar serializar um objeto enorme que requer um buffer maior que buffer.constants.MAX_LENGTH.

v8.deserialize(buffer)

Adicionado em: v8.0.0

Usa um DefaultDeserializer com opções padrão para ler um valor JS de um buffer.

Classe: v8.Serializer

Adicionado em: v8.0.0

new Serializer()

Cria um novo objeto Serializer.

serializer.writeHeader()

Escreve um cabeçalho, que inclui a versão do formato de serialização.

serializer.writeValue(value)

Serializa um valor JavaScript e adiciona a representação serializada ao buffer interno.

Isso lança um erro se value não puder ser serializado.

serializer.releaseBuffer()

Retorna o buffer interno armazenado. Este serializador não deve ser usado após a liberação do buffer. Chamar este método resulta em comportamento indefinido se uma gravação anterior falhou.

serializer.transferArrayBuffer(id, arrayBuffer)

Marca um ArrayBuffer como tendo seu conteúdo transferido fora da banda. Passe o ArrayBuffer correspondente no contexto de desserialização para deserializer.transferArrayBuffer().

serializer.writeUint32(value)

Escreve um inteiro não assinado bruto de 32 bits. Para uso dentro de um serializer._writeHostObject() personalizado.

serializer.writeUint64(hi, lo)

Escreve um inteiro não assinado bruto de 64 bits, dividido em partes altas e baixas de 32 bits. Para uso dentro de um serializer._writeHostObject() personalizado.

serializer.writeDouble(value)

Escreve um valor number JS. Para uso dentro de um serializer._writeHostObject() personalizado.

serializer.writeRawBytes(buffer)

Escreve bytes brutos no buffer interno do serializador. O desserializador exigirá uma forma de computar o comprimento do buffer. Para uso dentro de um serializer._writeHostObject() personalizado.

serializer._writeHostObject(object)

Este método é chamado para escrever algum tipo de objeto hospedeiro, ou seja, um objeto criado por ligações C++ nativas. Se não for possível serializar object, uma exceção adequada deve ser lançada.

Este método não está presente na própria classe Serializer, mas pode ser fornecido por subclasses.

serializer._getDataCloneError(message)

Este método é chamado para gerar objetos de erro que serão lançados quando um objeto não puder ser clonado.

Este método assume como padrão o construtor Error e pode ser substituído em subclasses.

serializer._getSharedArrayBufferId(sharedArrayBuffer)

Este método é chamado quando o serializador está prestes a serializar um objeto SharedArrayBuffer. Ele deve retornar um ID inteiro de 32 bits não assinado para o objeto, usando o mesmo ID se este SharedArrayBuffer já tiver sido serializado. Ao desserializar, este ID será passado para deserializer.transferArrayBuffer().

Se o objeto não puder ser serializado, uma exceção deverá ser lançada.

Este método não está presente na própria classe Serializer, mas pode ser fornecido por subclasses.

serializer._setTreatArrayBufferViewsAsHostObjects(flag)

Indica se os objetos TypedArray e DataView devem ser tratados como objetos hospedeiros, ou seja, passá-los para serializer._writeHostObject().

Classe: v8.Deserializer

Adicionado em: v8.0.0

new Deserializer(buffer)

Cria um novo objeto Deserializer.

deserializer.readHeader()

Lê e valida um cabeçalho (incluindo a versão do formato). Pode, por exemplo, rejeitar um formato de fio inválido ou não suportado. Nesse caso, um Error é lançado.

deserializer.readValue()

Desserializa um valor JavaScript do buffer e o retorna.

deserializer.transferArrayBuffer(id, arrayBuffer)

Marca um ArrayBuffer como tendo seu conteúdo transferido fora de banda. Passe o ArrayBuffer correspondente no contexto de serialização para serializer.transferArrayBuffer() (ou retorne o id de serializer._getSharedArrayBufferId() no caso de SharedArrayBuffers).

deserializer.getWireFormatVersion()

Lê a versão do formato wire subjacente. Provavelmente, será mais útil para código legado que lê versões antigas do formato wire. Pode não ser chamado antes de .readHeader().

deserializer.readUint32()

Lê um inteiro não assinado bruto de 32 bits e o retorna. Para uso dentro de um deserializer._readHostObject() personalizado.

deserializer.readUint64()

Lê um inteiro não assinado bruto de 64 bits e o retorna como um array [hi, lo] com duas entradas inteiras não assinadas de 32 bits. Para uso dentro de um deserializer._readHostObject() personalizado.

deserializer.readDouble()

Lê um valor number do JS. Para uso dentro de um deserializer._readHostObject() personalizado.

deserializer.readRawBytes(length)

Lê bytes brutos do buffer interno do deserializador. O parâmetro length deve corresponder ao comprimento do buffer que foi passado para serializer.writeRawBytes(). Para uso dentro de um deserializer._readHostObject() personalizado.

deserializer._readHostObject()

Este método é chamado para ler algum tipo de objeto host, ou seja, um objeto criado por ligações C++ nativas. Se não for possível desserializar os dados, uma exceção adequada deve ser lançada.

Este método não está presente na própria classe Deserializer, mas pode ser fornecido por subclasses.

Classe: v8.DefaultSerializer

Adicionado em: v8.0.0

Uma subclasse de Serializer que serializa objetos TypedArray (em particular Buffer) e DataView como objetos hospedeiros e armazena apenas a parte de seus ArrayBuffers subjacentes aos quais eles estão se referindo.

Classe: v8.DefaultDeserializer

Adicionado em: v8.0.0

Uma subclasse de Deserializer correspondente ao formato gravado por DefaultSerializer.

Hooks de promessa

A interface promiseHooks pode ser usada para rastrear eventos do ciclo de vida da promessa. Para rastrear toda a atividade assíncrona, veja async_hooks que internamente usa este módulo para produzir eventos do ciclo de vida da promessa, além de eventos para outros recursos assíncronos. Para o gerenciamento de contexto de solicitação, veja AsyncLocalStorage.

js
import { promiseHooks } from 'node:v8';

// Existem quatro eventos de ciclo de vida produzidos por promessas:

// O evento `init` representa a criação de uma promessa. Isso pode ser uma
// criação direta, como com `new Promise(...)`, ou uma continuação como
// `then()` ou `catch()`. Também acontece sempre que uma função assíncrona é
// chamada ou faz um `await`. Se uma promessa de continuação for criada, o
// `parent` será a promessa da qual é uma continuação.
function init(promise, parent) {
  console.log('uma promessa foi criada', { promise, parent });
}

// O evento `settled` acontece quando uma promessa recebe uma resolução ou
// valor de rejeição. Isso pode acontecer de forma síncrona, como ao usar
// `Promise.resolve()` em uma entrada que não seja uma promessa.
function settled(promise) {
  console.log('uma promessa foi resolvida ou rejeitada', { promise });
}

// O evento `before` é executado imediatamente antes de um manipulador `then()` ou `catch()`
// ser executado ou um `await` retomar a execução.
function before(promise) {
  console.log('uma promessa está prestes a chamar um manipulador then', { promise });
}

// O evento `after` é executado imediatamente após a execução de um manipulador `then()` ou quando
// um `await` começa após a retomada de outro.
function after(promise) {
  console.log('uma promessa terminou de chamar um manipulador then', { promise });
}

// Os hooks do ciclo de vida podem ser iniciados e interrompidos individualmente
const stopWatchingInits = promiseHooks.onInit(init);
const stopWatchingSettleds = promiseHooks.onSettled(settled);
const stopWatchingBefores = promiseHooks.onBefore(before);
const stopWatchingAfters = promiseHooks.onAfter(after);

// Ou eles podem ser iniciados e interrompidos em grupos
const stopHookSet = promiseHooks.createHook({
  init,
  settled,
  before,
  after,
});

// Para interromper um hook, chame a função retornada em sua criação.
stopWatchingInits();
stopWatchingSettleds();
stopWatchingBefores();
stopWatchingAfters();
stopHookSet();

promiseHooks.onInit(init)

Adicionado em: v17.1.0, v16.14.0

O hook init deve ser uma função simples. Fornecer uma função async irá lançar um erro, pois produziria um loop infinito de microtarefas.

js
import { promiseHooks } from 'node:v8';

const stop = promiseHooks.onInit((promise, parent) => {});
js
const { promiseHooks } = require('node:v8');

const stop = promiseHooks.onInit((promise, parent) => {});

promiseHooks.onSettled(settled)

Adicionado em: v17.1.0, v16.14.0

O hook settled deve ser uma função simples. Fornecer uma função async irá lançar um erro, pois produziria um loop infinito de microtarefas.

js
import { promiseHooks } from 'node:v8';

const stop = promiseHooks.onSettled((promise) => {});
js
const { promiseHooks } = require('node:v8');

const stop = promiseHooks.onSettled((promise) => {});

promiseHooks.onBefore(before)

Adicionado em: v17.1.0, v16.14.0

O hook before deve ser uma função simples. Fornecer uma função async irá lançar um erro, pois produziria um loop infinito de microtarefas.

js
import { promiseHooks } from 'node:v8';

const stop = promiseHooks.onBefore((promise) => {});
js
const { promiseHooks } = require('node:v8');

const stop = promiseHooks.onBefore((promise) => {});

promiseHooks.onAfter(after)

Adicionado em: v17.1.0, v16.14.0

O hook after deve ser uma função simples. Fornecer uma função async lançará um erro, pois produziria um loop de microtarefas infinito.

js
import { promiseHooks } from 'node:v8';

const stop = promiseHooks.onAfter((promise) => {});
js
const { promiseHooks } = require('node:v8');

const stop = promiseHooks.onAfter((promise) => {});

promiseHooks.createHook(callbacks)

Adicionado em: v17.1.0, v16.14.0

Os callbacks do hook devem ser funções simples. Fornecer funções async lançará um erro, pois produziria um loop de microtarefas infinito.

Registra funções para serem chamadas para diferentes eventos de ciclo de vida de cada promise.

Os callbacks init()/before()/after()/settled() são chamados para os respectivos eventos durante o ciclo de vida de uma promise.

Todos os callbacks são opcionais. Por exemplo, se apenas a criação de promises precisar ser rastreada, apenas o callback init precisa ser passado. Os detalhes de todas as funções que podem ser passadas para callbacks estão na seção Callbacks do Hook.

js
import { promiseHooks } from 'node:v8';

const stopAll = promiseHooks.createHook({
  init(promise, parent) {},
});
js
const { promiseHooks } = require('node:v8');

const stopAll = promiseHooks.createHook({
  init(promise, parent) {},
});

Callbacks de Hook

Os principais eventos no ciclo de vida de uma promise foram categorizados em quatro áreas: criação de uma promise, antes/depois que um manipulador de continuação é chamado ou em torno de um await, e quando a promise resolve ou rejeita.

Embora esses hooks sejam semelhantes aos de async_hooks, eles não possuem um hook destroy. Outros tipos de recursos assíncronos normalmente representam sockets ou descritores de arquivos que possuem um estado "fechado" distinto para expressar o evento do ciclo de vida destroy, enquanto as promises permanecem utilizáveis ​​enquanto o código ainda puder alcançá-las. O rastreamento de coleta de lixo é usado para fazer com que as promises se encaixem no modelo de eventos async_hooks, no entanto, esse rastreamento é muito caro e elas podem nem mesmo ser coletadas pelo lixo.

Como as promises são recursos assíncronos cujo ciclo de vida é rastreado por meio do mecanismo de hooks de promise, os callbacks init(), before(), after() e settled() não devem ser funções assíncronas, pois criam mais promises que produziriam um loop infinito.

Embora esta API seja usada para alimentar eventos de promise em async_hooks, a ordem entre os dois é indefinida. Ambas as APIs são multi-inquilino e, portanto, podem produzir eventos em qualquer ordem em relação umas às outras.

init(promise, parent)

  • promise <Promise> A promise sendo criada.
  • parent <Promise> A promise continuada de, se aplicável.

Chamado quando uma promise é construída. Isso não significa que os eventos before/after correspondentes ocorrerão, apenas que a possibilidade existe. Isso acontecerá se uma promise for criada sem nunca obter uma continuação.

before(promise)

Chamado antes que uma continuação de promise seja executada. Isso pode ser na forma de manipuladores then(), catch() ou finally() ou um await retomando.

O callback before será chamado de 0 a N vezes. O callback before normalmente será chamado 0 vezes se nenhuma continuação foi feita para a promise. O callback before pode ser chamado muitas vezes no caso em que muitas continuações foram feitas a partir da mesma promise.

after(promise)

Chamado imediatamente após a execução de uma continuação de promise. Isso pode ser depois de um manipulador then(), catch() ou finally() ou antes de um await após outro await.

settled(promise)

Chamado quando a promise recebe um valor de resolução ou rejeição. Isso pode ocorrer de forma síncrona no caso de Promise.resolve() ou Promise.reject().

API de Snapshot de Inicialização

Adicionado em: v18.6.0, v16.17.0

[Estável: 1 - Experimental]

Estável: 1 Estabilidade: 1 - Experimental

A interface v8.startupSnapshot pode ser usada para adicionar hooks de serialização e desserialização para snapshots de inicialização personalizados.

bash
$ node --snapshot-blob snapshot.blob --build-snapshot entry.js
# Isso inicia um processo com o snapshot {#this-launches-a-process-with-the-snapshot}
$ node --snapshot-blob snapshot.blob

No exemplo acima, entry.js pode usar métodos da interface v8.startupSnapshot para especificar como salvar informações para objetos personalizados no snapshot durante a serialização e como as informações podem ser usadas para sincronizar esses objetos durante a desserialização do snapshot. Por exemplo, se o entry.js contiver o seguinte script:

js
'use strict';

const fs = require('node:fs');
const zlib = require('node:zlib');
const path = require('node:path');
const assert = require('node:assert');

const v8 = require('node:v8');

class BookShelf {
  storage = new Map();

  // Lendo uma série de arquivos do diretório e armazenando-os no armazenamento.
  constructor(directory, books) {
    for (const book of books) {
      this.storage.set(book, fs.readFileSync(path.join(directory, book)));
    }
  }

  static compressAll(shelf) {
    for (const [ book, content ] of shelf.storage) {
      shelf.storage.set(book, zlib.gzipSync(content));
    }
  }

  static decompressAll(shelf) {
    for (const [ book, content ] of shelf.storage) {
      shelf.storage.set(book, zlib.gunzipSync(content));
    }
  }
}

// __dirname aqui é onde o script de snapshot é colocado
// durante o tempo de construção do snapshot.
const shelf = new BookShelf(__dirname, [
  'book1.en_US.txt',
  'book1.es_ES.txt',
  'book2.zh_CN.txt',
]);

assert(v8.startupSnapshot.isBuildingSnapshot());
// Na serialização do snapshot, comprima os livros para reduzir o tamanho.
v8.startupSnapshot.addSerializeCallback(BookShelf.compressAll, shelf);
// Na desserialização do snapshot, descomprima os livros.
v8.startupSnapshot.addDeserializeCallback(BookShelf.decompressAll, shelf);
v8.startupSnapshot.setDeserializeMainFunction((shelf) => {
  // process.env e process.argv são atualizados durante o snapshot
  // desserialização.
  const lang = process.env.BOOK_LANG || 'en_US';
  const book = process.argv[1];
  const name = `${book}.${lang}.txt`;
  console.log(shelf.storage.get(name));
}, shelf);

O binário resultante imprimirá os dados desserializados do snapshot durante a inicialização, usando os process.env e process.argv atualizados do processo iniciado:

bash
$ BOOK_LANG=es_ES node --snapshot-blob snapshot.blob book1
# Imprime o conteúdo de book1.es_ES.txt desserializado do snapshot. {#prints-content-of-book1es_estxt-deserialized-from-the-snapshot}

Atualmente, o aplicativo desserializado de um snapshot do espaço do usuário não pode ser novamente capturado, portanto, essas APIs estão disponíveis apenas para aplicativos que não são desserializados de um snapshot do espaço do usuário.

v8.startupSnapshot.addSerializeCallback(callback[, data])

Adicionado em: v18.6.0, v16.17.0

  • callback <Function> Callback a ser invocado antes da serialização.
  • data <any> Dados opcionais que serão passados para o callback quando for chamado.

Adiciona um callback que será chamado quando a instância Node.js estiver prestes a ser serializada em um snapshot e sair. Isso pode ser usado para liberar recursos que não devem ou não podem ser serializados ou para converter dados do usuário em um formato mais adequado para serialização.

Os callbacks são executados na ordem em que são adicionados.

v8.startupSnapshot.addDeserializeCallback(callback[, data])

Adicionado em: v18.6.0, v16.17.0

  • callback <Function> Callback a ser invocado após a desserialização do snapshot.
  • data <any> Dados opcionais que serão passados para o callback quando for chamado.

Adiciona um callback que será chamado quando a instância Node.js for desserializada de um snapshot. O callback e os data (se fornecidos) serão serializados no snapshot, eles podem ser usados para reinicializar o estado do aplicativo ou para readquirir os recursos de que o aplicativo precisa quando o aplicativo é reiniciado do snapshot.

Os callbacks são executados na ordem em que são adicionados.

v8.startupSnapshot.setDeserializeMainFunction(callback[, data])

Adicionado em: v18.6.0, v16.17.0

  • callback <Function> Callback a ser invocado como o ponto de entrada após a desserialização do snapshot.
  • data <any> Dados opcionais que serão passados para o callback quando for chamado.

Isso define o ponto de entrada do aplicativo Node.js quando ele é desserializado de um snapshot. Isso pode ser chamado apenas uma vez no script de construção do snapshot. Se chamado, o aplicativo desserializado não precisa mais de um script de ponto de entrada adicional para iniciar e simplesmente invocará o callback junto com os dados desserializados (se fornecidos), caso contrário, um script de ponto de entrada ainda precisa ser fornecido ao aplicativo desserializado.

v8.startupSnapshot.isBuildingSnapshot()

Adicionado em: v18.6.0, v16.17.0

Retorna verdadeiro se a instância do Node.js for executada para construir um snapshot.

Classe: v8.GCProfiler

Adicionado em: v19.6.0, v18.15.0

Esta API coleta dados de GC na thread atual.

new v8.GCProfiler()

Adicionado em: v19.6.0, v18.15.0

Cria uma nova instância da classe v8.GCProfiler.

profiler.start()

Adicionado em: v19.6.0, v18.15.0

Começa a coletar dados de GC.

profiler.stop()

Adicionado em: v19.6.0, v18.15.0

Para de coletar dados de GC e retorna um objeto. O conteúdo do objeto é o seguinte.

json
{
  "version": 1,
  "startTime": 1674059033862,
  "statistics": [
    {
      "gcType": "Scavenge",
      "beforeGC": {
        "heapStatistics": {
          "totalHeapSize": 5005312,
          "totalHeapSizeExecutable": 524288,
          "totalPhysicalSize": 5226496,
          "totalAvailableSize": 4341325216,
          "totalGlobalHandlesSize": 8192,
          "usedGlobalHandlesSize": 2112,
          "usedHeapSize": 4883840,
          "heapSizeLimit": 4345298944,
          "mallocedMemory": 254128,
          "externalMemory": 225138,
          "peakMallocedMemory": 181760
        },
        "heapSpaceStatistics": [
          {
            "spaceName": "read_only_space",
            "spaceSize": 0,
            "spaceUsedSize": 0,
            "spaceAvailableSize": 0,
            "physicalSpaceSize": 0
          }
        ]
      },
      "cost": 1574.14,
      "afterGC": {
        "heapStatistics": {
          "totalHeapSize": 6053888,
          "totalHeapSizeExecutable": 524288,
          "totalPhysicalSize": 5500928,
          "totalAvailableSize": 4341101384,
          "totalGlobalHandlesSize": 8192,
          "usedGlobalHandlesSize": 2112,
          "usedHeapSize": 4059096,
          "heapSizeLimit": 4345298944,
          "mallocedMemory": 254128,
          "externalMemory": 225138,
          "peakMallocedMemory": 181760
        },
        "heapSpaceStatistics": [
          {
            "spaceName": "read_only_space",
            "spaceSize": 0,
            "spaceUsedSize": 0,
            "spaceAvailableSize": 0,
            "physicalSpaceSize": 0
          }
        ]
      }
    }
  ],
  "endTime": 1674059036865
}

Aqui está um exemplo.

js
const { GCProfiler } = require('node:v8');
const profiler = new GCProfiler();
profiler.start();
setTimeout(() => {
  console.log(profiler.stop());
}, 1000);