Skip to content

V8

Código fuente: lib/v8.js

El módulo node:v8 expone APIs que son específicas de la versión de V8 integrada en el binario de Node.js. Se puede acceder usando:

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

v8.cachedDataVersionTag()

Agregado en: v8.0.0

Regresa un entero que representa una etiqueta de versión derivada de la versión de V8, los flags de línea de comandos y las características detectadas de la CPU. Esto es útil para determinar si un búfer cachedData de vm.Script es compatible con esta instancia de V8.

js
console.log(v8.cachedDataVersionTag()); // 3947234607
// El valor regresado por v8.cachedDataVersionTag() se deriva de la versión
// de V8, los flags de línea de comandos y las características detectadas de la CPU.
// Prueba que el valor se actualice cuando los flags se activen/desactiven.
v8.setFlagsFromString('--allow_natives_syntax');
console.log(v8.cachedDataVersionTag()); // 183726201

v8.getHeapCodeStatistics()

Agregado en: v12.8.0

Obtén estadísticas sobre el código y sus metadatos en el heap, mira la API GetHeapCodeAndMetadataStatistics de V8. Regresa un objeto con las siguientes propiedades:

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

v8.getHeapSnapshot([options])

[Historial]

VersiónCambios
v19.1.0Soporte para opciones para configurar la captura de montón.
v11.13.0Añadido en: v11.13.0
  • options <Objeto>

    • exposeInternals <booleano> Si es true, expone los elementos internos en la captura del montón. Predeterminado: false.
    • exposeNumericValues <booleano> Si es true, expone los valores numéricos en campos artificiales. Predeterminado: false.
  • Devuelve: <stream.Readable> Un Readable que contiene la captura de montón de V8.

Genera una captura del montón V8 actual y devuelve un flujo Readable que se puede utilizar para leer la representación serializada JSON. Este formato de flujo JSON está destinado a ser utilizado con herramientas como Chrome DevTools. El esquema JSON no está documentado y es específico del motor V8. Por lo tanto, el esquema puede cambiar de una versión de V8 a la siguiente.

Crear una captura de montón requiere una memoria aproximadamente dos veces el tamaño del montón en el momento en que se crea la captura. Esto resulta en el riesgo de que los terminadores OOM terminen el proceso.

Generar una captura es una operación síncrona que bloquea el bucle de eventos durante una duración que depende del tamaño del montón.

js
// Imprime la captura del montón en la consola
const v8 = require('node:v8');
const stream = v8.getHeapSnapshot();
stream.pipe(process.stdout);

v8.getHeapSpaceStatistics()

[Historial]

VersiónCambios
v7.5.0Soporte para valores que exceden el rango de enteros sin signo de 32 bits.
v6.0.0Añadido en: v6.0.0

Devuelve estadísticas sobre los espacios de montón de V8, es decir, los segmentos que componen el montón de V8. Ni el orden de los espacios de montón, ni la disponibilidad de un espacio de montón pueden garantizarse ya que las estadísticas se proporcionan a través de la función V8 GetHeapSpaceStatistics y puede cambiar de una versión de V8 a la siguiente.

El valor devuelto es una matriz de objetos que contienen las siguientes propiedades:

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

[Historial]

VersiónCambios
v7.5.0Soporta valores que exceden el rango entero sin signo de 32 bits.
v7.2.0Se agregaron malloced_memory, peak_malloced_memory y does_zap_garbage.
v1.0.0Agregado en: v1.0.0

Devuelve un objeto con las siguientes propiedades:

total_heap_size El valor de total_heap_size es el número de bytes que V8 ha asignado para el heap. Esto puede crecer si used_heap necesita más memoria.

total_heap_size_executable El valor de total_heap_size_executable es la porción del heap que puede contener código ejecutable, en bytes. Esto incluye la memoria utilizada por el código compilado con JIT y cualquier memoria que deba mantenerse ejecutable.

total_physical_size El valor de total_physical_size es la memoria física real utilizada por el heap de V8, en bytes. Esta es la cantidad de memoria que se confirma (o en uso) en lugar de reservada.

total_available_size El valor de total_available_size es el número de bytes de memoria disponibles para el heap de V8. Este valor representa cuánta memoria más puede usar V8 antes de exceder el límite del heap.

used_heap_size El valor de used_heap_size es el número de bytes que están utilizando actualmente los objetos JavaScript de V8. Esta es la memoria real en uso y no incluye la memoria que se ha asignado pero aún no se ha utilizado.

heap_size_limit El valor de heap_size_limit es el tamaño máximo del heap de V8, en bytes (ya sea el límite predeterminado, determinado por los recursos del sistema, o el valor pasado a la opción --max_old_space_size).

malloced_memory El valor de malloced_memory es el número de bytes asignados a través de malloc por V8.

peak_malloced_memory El valor de peak_malloced_memory es el número máximo de bytes asignados a través de malloc por V8 durante la vida útil del proceso.

does_zap_garbage es un booleano 0/1, que indica si la opción --zap_code_space está habilitada o no. Esto hace que V8 sobrescriba la basura del montón con un patrón de bits. La huella RSS (tamaño del conjunto residente) se hace más grande porque toca continuamente todas las páginas del montón y eso hace que sea menos probable que el sistema operativo las intercambie.

number_of_native_contexts El valor de native_context es el número de contextos de nivel superior actualmente activos. El aumento de este número con el tiempo indica una fuga de memoria.

number_of_detached_contexts El valor de detached_context es el número de contextos que se separaron y aún no se recolectaron como basura. Que este número sea distinto de cero indica una posible fuga de memoria.

total_global_handles_size El valor de total_global_handles_size es el tamaño total de la memoria de los identificadores globales de V8.

used_global_handles_size El valor de used_global_handles_size es el tamaño de la memoria utilizada de los identificadores globales de V8.

external_memory El valor de external_memory es el tamaño de la memoria de los búferes de matriz y las cadenas 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])

Agregado en: v22.0.0, v20.13.0

[Estable: 1 - Experimental]

Estable: 1 Estabilidad: 1.1 - Desarrollo activo

  • ctor <Function> El constructor que se puede utilizar para buscar en la cadena de prototipos para filtrar los objetos objetivo en el montón.

  • options <undefined> | <Object>

    • format <string> Si es 'count', se devuelve el recuento de objetos coincidentes. Si es 'summary', se devuelve un array con cadenas de resumen de los objetos coincidentes.
  • Devuelve: {number|Array

Esto es similar a la queryObjects() API de la consola proporcionada por la consola de Chromium DevTools. Se puede utilizar para buscar objetos que tienen el constructor coincidente en su cadena de prototipos en el montón después de una recolección completa de basura, lo que puede ser útil para las pruebas de regresión de fugas de memoria. Para evitar resultados sorprendentes, los usuarios deben evitar el uso de esta API en constructores cuya implementación no controlan, o en constructores que pueden ser invocados por otras partes en la aplicación.

Para evitar fugas accidentales, esta API no devuelve referencias sin procesar a los objetos encontrados. De forma predeterminada, devuelve el recuento de los objetos encontrados. Si options.format es 'summary', devuelve un array que contiene representaciones de cadena breves para cada objeto. La visibilidad proporcionada en esta API es similar a la que proporciona la instantánea del montón, mientras que los usuarios pueden ahorrar el costo de la serialización y el análisis y filtrar directamente los objetos objetivo durante la búsqueda.

Solo los objetos creados en el contexto de ejecución actual se incluyen en los 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)

Añadido en: v1.0.0

El método v8.setFlagsFromString() se puede usar para establecer indicadores de línea de comandos de V8 de forma programática. Este método se debe utilizar con precaución. Cambiar la configuración después de que la VM se haya iniciado puede provocar un comportamiento impredecible, incluidos bloqueos y pérdida de datos; o simplemente puede que no haga nada.

Las opciones de V8 disponibles para una versión de Node.js se pueden determinar ejecutando node --v8-options.

Uso:

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

v8.stopCoverage()

Añadido en: v15.1.0, v14.18.0, v12.22.0

El método v8.stopCoverage() permite al usuario detener la recopilación de cobertura iniciada por NODE_V8_COVERAGE, para que V8 pueda liberar los registros de recuento de ejecución y optimizar el código. Esto se puede usar junto con v8.takeCoverage() si el usuario desea recopilar la cobertura bajo demanda.

v8.takeCoverage()

Añadido en: v15.1.0, v14.18.0, v12.22.0

El método v8.takeCoverage() permite al usuario escribir la cobertura iniciada por NODE_V8_COVERAGE en el disco bajo demanda. Este método se puede invocar varias veces durante la vida útil del proceso. Cada vez que se restablece el contador de ejecución y se escribe un nuevo informe de cobertura en el directorio especificado por NODE_V8_COVERAGE.

Cuando el proceso está a punto de salir, todavía se escribirá una última cobertura en el disco a menos que se invoque v8.stopCoverage() antes de que el proceso salga.

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

[Historial]

VersiónCambios
v19.1.0Soporta opciones para configurar la captura del montón.
v18.0.0Ahora se lanzará una excepción si el archivo no se pudo escribir.
v18.0.0Hace que los códigos de error devueltos sean consistentes en todas las plataformas.
v11.13.0Añadido en: v11.13.0
  • filename <string> La ruta del archivo donde se guardará la instantánea del montón de V8. Si no se especifica, se generará un nombre de archivo con el patrón 'Heap-${yyyymmdd}-${hhmmss}-${pid}-${thread_id}.heapsnapshot', donde {pid} será el PID del proceso de Node.js, {thread_id} será 0 cuando se llame a writeHeapSnapshot() desde el hilo principal de Node.js o la ID de un hilo de trabajo.

  • options <Object>

    • exposeInternals <boolean> Si es true, expone los internos en la instantánea del montón. Predeterminado: false.
    • exposeNumericValues <boolean> Si es true, expone valores numéricos en campos artificiales. Predeterminado: false.
  • Devuelve: <string> El nombre del archivo donde se guardó la instantánea.

Genera una instantánea del montón V8 actual y la escribe en un archivo JSON. Este archivo está destinado a ser utilizado con herramientas como Chrome DevTools. El esquema JSON no está documentado y es específico del motor V8, y puede cambiar de una versión de V8 a la siguiente.

Una instantánea de montón es específica de un único aislamiento de V8. Cuando se usan hilos de trabajo, una instantánea de montón generada desde el hilo principal no contendrá ninguna información sobre los trabajadores, y viceversa.

Crear una instantánea de montón requiere memoria aproximadamente el doble del tamaño del montón en el momento en que se crea la instantánea. Esto resulta en el riesgo de que los terminadores OOM terminen el proceso.

Generar una instantánea es una operación síncrona que bloquea el bucle de eventos durante una duración que depende del tamaño del montón.

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}`);
    // Now get a heapdump for the main thread.
    console.log(`main thread heapdump: ${writeHeapSnapshot()}`);
  });

  // Tell the worker to create a heapdump.
  worker.postMessage('heapdump');
} else {
  parentPort.once('message', (message) => {
    if (message === 'heapdump') {
      // Generate a heapdump for the worker
      // and return the filename to the parent.
      parentPort.postMessage(writeHeapSnapshot());
    }
  });
}

v8.setHeapSnapshotNearHeapLimit(limit)

Agregado en: v18.10.0, v16.18.0

[Stable: 1 - Experimental]

Stable: 1 Estable: 1 - Experimental

La API es una no-operación si --heapsnapshot-near-heap-limit ya está establecido desde la línea de comandos o si la API se llama más de una vez. limit debe ser un entero positivo. Consulte --heapsnapshot-near-heap-limit para obtener más información.

API de serialización

La API de serialización proporciona medios para serializar valores de JavaScript de una manera que sea compatible con el algoritmo de clonación estructurada HTML.

El formato es compatible con versiones anteriores (es decir, seguro para almacenar en el disco). Valores iguales de JavaScript pueden resultar en una salida serializada diferente.

v8.serialize(value)

Agregado en: v8.0.0

Utiliza un DefaultSerializer para serializar value en un búfer.

ERR_BUFFER_TOO_LARGE se lanzará al intentar serializar un objeto enorme que requiere un búfer más grande que buffer.constants.MAX_LENGTH.

v8.deserialize(buffer)

Agregado en: v8.0.0

Utiliza un DefaultDeserializer con opciones predeterminadas para leer un valor JS de un búfer.

Clase: v8.Serializer

Agregado en: v8.0.0

new Serializer()

Crea un nuevo objeto Serializer.

serializer.writeHeader()

Escribe un encabezado, que incluye la versión del formato de serialización.

serializer.writeValue(value)

Serializa un valor de JavaScript y agrega la representación serializada al búfer interno.

Esto arroja un error si value no se puede serializar.

serializer.releaseBuffer()

Devuelve el búfer interno almacenado. Este serializador no debe usarse una vez que se libera el búfer. Llamar a este método resulta en un comportamiento indefinido si una escritura anterior ha fallado.

serializer.transferArrayBuffer(id, arrayBuffer)

Marca un ArrayBuffer como que su contenido se ha transferido fuera de banda. Pase el ArrayBuffer correspondiente en el contexto de deserialización a deserializer.transferArrayBuffer().

serializer.writeUint32(value)

Escribe un entero sin signo de 32 bits sin procesar. Para usar dentro de un serializer._writeHostObject() personalizado.

serializer.writeUint64(hi, lo)

Escribe un entero sin signo de 64 bits sin procesar, dividido en partes altas y bajas de 32 bits. Para usar dentro de un serializer._writeHostObject() personalizado.

serializer.writeDouble(value)

Escribe un valor number de JS. Para usar dentro de un serializer._writeHostObject() personalizado.

serializer.writeRawBytes(buffer)

Escribe bytes sin formato en el búfer interno del serializador. El deserializador requerirá una forma de calcular la longitud del búfer. Para usar dentro de un serializer._writeHostObject() personalizado.

serializer._writeHostObject(object)

Este método se llama para escribir algún tipo de objeto host, es decir, un objeto creado por enlaces nativos de C++. Si no es posible serializar object, se debe lanzar una excepción adecuada.

Este método no está presente en la clase Serializer en sí, pero puede ser proporcionado por subclases.

serializer._getDataCloneError(message)

Este método se llama para generar objetos de error que se lanzarán cuando un objeto no se pueda clonar.

Este método por defecto es el constructor Error y puede ser sobrescrito en subclases.

serializer._getSharedArrayBufferId(sharedArrayBuffer)

Este método se llama cuando el serializador va a serializar un objeto SharedArrayBuffer. Debe devolver un ID entero de 32 bits sin signo para el objeto, utilizando el mismo ID si este SharedArrayBuffer ya ha sido serializado. Al deserializar, este ID se pasará a deserializer.transferArrayBuffer().

Si el objeto no se puede serializar, se debe lanzar una excepción.

Este método no está presente en la clase Serializer en sí, pero puede ser proporcionado por subclases.

serializer._setTreatArrayBufferViewsAsHostObjects(flag)

Indica si se deben tratar los objetos TypedArray y DataView como objetos host, es decir, pasarlos a serializer._writeHostObject().

Clase: v8.Deserializer

Agregado en: v8.0.0

new Deserializer(buffer)

Crea un nuevo objeto Deserializer.

deserializer.readHeader()

Lee y valida un encabezado (incluida la versión del formato). Puede, por ejemplo, rechazar un formato de cableado no válido o no admitido. En ese caso, se lanza un Error.

deserializer.readValue()

Deserializa un valor de JavaScript del búfer y lo devuelve.

deserializer.transferArrayBuffer(id, arrayBuffer)

Marca un ArrayBuffer como si su contenido se hubiera transferido fuera de banda. Pasa el ArrayBuffer correspondiente en el contexto de serialización a serializer.transferArrayBuffer() (o devuelve el id de serializer._getSharedArrayBufferId() en el caso de SharedArrayBuffers).

deserializer.getWireFormatVersion()

Lee la versión del formato de cable subyacente. Es probable que sea más útil para el código heredado que lee versiones antiguas del formato de cable. Es posible que no se llame antes de .readHeader().

deserializer.readUint32()

Lee un entero sin signo de 32 bits sin formato y lo devuelve. Para usar dentro de un deserializer._readHostObject() personalizado.

deserializer.readUint64()

Lee un entero sin signo de 64 bits sin formato y lo devuelve como un array [hi, lo] con dos entradas de entero sin signo de 32 bits. Para usar dentro de un deserializer._readHostObject() personalizado.

deserializer.readDouble()

Lee un valor number de JS. Para usar dentro de un deserializer._readHostObject() personalizado.

deserializer.readRawBytes(length)

Lee bytes sin formato del búfer interno del deserializador. El parámetro length debe corresponder a la longitud del búfer que se pasó a serializer.writeRawBytes(). Para usar dentro de un deserializer._readHostObject() personalizado.

deserializer._readHostObject()

Este método se llama para leer algún tipo de objeto host, es decir, un objeto que es creado por enlaces nativos de C++. Si no es posible deserializar los datos, se debe lanzar una excepción adecuada.

Este método no está presente en la propia clase Deserializer, pero puede ser proporcionado por subclases.

Clase: v8.DefaultSerializer

Agregado en: v8.0.0

Una subclase de Serializer que serializa objetos TypedArray (en particular Buffer) y DataView como objetos host, y solo almacena la parte de sus ArrayBuffer subyacentes a las que se refieren.

Clase: v8.DefaultDeserializer

Agregado en: v8.0.0

Una subclase de Deserializer correspondiente al formato escrito por DefaultSerializer.

Enlaces de Promise

La interfaz promiseHooks se puede utilizar para rastrear los eventos del ciclo de vida de las promesas. Para rastrear toda la actividad asíncrona, consulte async_hooks que internamente utiliza este módulo para producir eventos del ciclo de vida de la promesa además de los eventos para otros recursos asíncronos. Para la gestión del contexto de la solicitud, consulte AsyncLocalStorage.

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

// Hay cuatro eventos del ciclo de vida producidos por las promesas:

// El evento `init` representa la creación de una promesa. Esto podría ser una
// creación directa como con `new Promise(...)` o una continuación como
// como `then()` o `catch()`. También ocurre cada vez que se llama a una función asíncrona o
// hace un `await`. Si se crea una promesa de continuación, el
// `parent` será la promesa de la que es una continuación.
function init(promise, parent) {
  console.log('se creó una promesa', { promise, parent });
}

// El evento `settled` ocurre cuando una promesa recibe una resolución o
// valor de rechazo. Esto puede suceder sincrónicamente, como cuando se usa
// `Promise.resolve()` en una entrada que no es promesa.
function settled(promise) {
  console.log('una promesa se resolvió o rechazó', { promise });
}

// El evento `before` se ejecuta inmediatamente antes de que se ejecute un controlador `then()` o `catch()`
// se ejecuta o un `await` reanuda la ejecución.
function before(promise) {
  console.log('una promesa está a punto de llamar a un controlador then', { promise });
}

// El evento `after` se ejecuta inmediatamente después de que se ejecuta un controlador `then()` o cuando
// un `await` comienza después de reanudar desde otro.
function after(promise) {
  console.log('una promesa terminó de llamar a un controlador then', { promise });
}

// Los enlaces del ciclo de vida se pueden iniciar y detener individualmente
const stopWatchingInits = promiseHooks.onInit(init);
const stopWatchingSettleds = promiseHooks.onSettled(settled);
const stopWatchingBefores = promiseHooks.onBefore(before);
const stopWatchingAfters = promiseHooks.onAfter(after);

// O pueden iniciarse y detenerse en grupos
const stopHookSet = promiseHooks.createHook({
  init,
  settled,
  before,
  after,
});

// Para detener un enlace, llame a la función devuelta en su creación.
stopWatchingInits();
stopWatchingSettleds();
stopWatchingBefores();
stopWatchingAfters();
stopHookSet();

promiseHooks.onInit(init)

Agregado en: v17.1.0, v16.14.0

El hook init debe ser una función simple. Proporcionar una función async lanzará un error ya que produciría un bucle de microtareas infinito.

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)

Agregado en: v17.1.0, v16.14.0

El hook settled debe ser una función simple. Proporcionar una función async lanzará un error ya que produciría un bucle de microtareas infinito.

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)

Agregado en: v17.1.0, v16.14.0

El hook before debe ser una función simple. Proporcionar una función async lanzará un error ya que produciría un bucle de microtareas infinito.

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)

Añadido en: v17.1.0, v16.14.0

El hook after debe ser una función simple. Proporcionar una función asíncrona lanzará un error, ya que produciría un bucle de microtareas 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)

Añadido en: v17.1.0, v16.14.0

Las callbacks de hook deben ser funciones simples. Proporcionar funciones asíncronas lanzará un error, ya que produciría un bucle de microtareas infinito.

Registra funciones para ser llamadas para diferentes eventos del ciclo de vida de cada promesa.

Las callbacks init()/before()/after()/settled() se llaman para los respectivos eventos durante el ciclo de vida de una promesa.

Todas las callbacks son opcionales. Por ejemplo, si solo es necesario rastrear la creación de promesas, entonces solo necesita pasarse la callback init. Los detalles de todas las funciones que se pueden pasar a callbacks están en la sección Hook Callbacks.

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) {},
});

Retrollamadas de Hook

Los eventos clave en el ciclo de vida de una promesa se han categorizado en cuatro áreas: creación de una promesa, antes/después de que se llame a un controlador de continuación o alrededor de un await, y cuando la promesa se resuelve o rechaza.

Si bien estos hooks son similares a los de async_hooks, carecen de un hook destroy. Otros tipos de recursos asíncronos suelen representar sockets o descriptores de archivo que tienen un estado "cerrado" distinto para expresar el evento del ciclo de vida destroy, mientras que las promesas siguen siendo utilizables mientras el código aún pueda alcanzarlas. El seguimiento de la recolección de basura se utiliza para hacer que las promesas encajen en el modelo de eventos async_hooks, sin embargo, este seguimiento es muy costoso y es posible que nunca se recolecten como basura.

Debido a que las promesas son recursos asíncronos cuyo ciclo de vida se rastrea a través del mecanismo de hooks de promesa, las retrollamadas init(), before(), after() y settled() no deben ser funciones async, ya que crean más promesas que producirían un bucle infinito.

Si bien esta API se utiliza para alimentar eventos de promesa en async_hooks, el orden entre los dos no está definido. Ambas API son multiinquilino y, por lo tanto, podrían producir eventos en cualquier orden entre sí.

init(promise, parent)

  • promise <Promise> La promesa que se está creando.
  • parent <Promise> La promesa continuada desde, si corresponde.

Se llama cuando se construye una promesa. Esto no significa que se producirán eventos before/after correspondientes, solo que existe la posibilidad. Esto sucederá si se crea una promesa sin obtener nunca una continuación.

before(promise)

Se llama antes de que se ejecute una continuación de promesa. Esto puede ser en forma de controladores then(), catch() o finally() o una reanudación de await.

La retrollamada before se llamará de 0 a N veces. La retrollamada before normalmente se llamará 0 veces si nunca se realizó ninguna continuación para la promesa. La retrollamada before se puede llamar muchas veces en el caso de que se hayan realizado muchas continuaciones desde la misma promesa.

after(promise)

Se llama inmediatamente después de que se ejecuta una continuación de promesa. Esto puede ser después de un controlador then(), catch() o finally() o antes de un await después de otro await.

settled(promise)

Se llama cuando la promesa recibe un valor de resolución o rechazo. Esto puede ocurrir sincrónicamente en el caso de Promise.resolve() o Promise.reject().

API de Instantánea de Inicio

Agregado en: v18.6.0, v16.17.0

[Estable: 1 - Experimental]

Estable: 1 Estabilidad: 1 - Experimental

La interfaz v8.startupSnapshot se puede utilizar para agregar hooks de serialización y deserialización para instantáneas de inicio personalizadas.

bash
$ node --snapshot-blob snapshot.blob --build-snapshot entry.js
# Esto inicia un proceso con la instantánea {#this-launches-a-process-with-the-snapshot}
$ node --snapshot-blob snapshot.blob

En el ejemplo anterior, entry.js puede usar métodos de la interfaz v8.startupSnapshot para especificar cómo guardar información para objetos personalizados en la instantánea durante la serialización y cómo la información se puede utilizar para sincronizar estos objetos durante la deserialización de la instantánea. Por ejemplo, si entry.js contiene el siguiente 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();

  // Reading a series of files from directory and store them into storage.
  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 here is where the snapshot script is placed
// during snapshot building time.
const shelf = new BookShelf(__dirname, [
  'book1.en_US.txt',
  'book1.es_ES.txt',
  'book2.zh_CN.txt',
]);

assert(v8.startupSnapshot.isBuildingSnapshot());
// On snapshot serialization, compress the books to reduce size.
v8.startupSnapshot.addSerializeCallback(BookShelf.compressAll, shelf);
// On snapshot deserialization, decompress the books.
v8.startupSnapshot.addDeserializeCallback(BookShelf.decompressAll, shelf);
v8.startupSnapshot.setDeserializeMainFunction((shelf) => {
  // process.env and process.argv are refreshed during snapshot
  // deserialization.
  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);

El binario resultante imprimirá los datos deserializados de la instantánea durante el inicio, utilizando los process.env y process.argv actualizados del proceso iniciado:

bash
$ BOOK_LANG=es_ES node --snapshot-blob snapshot.blob book1
# Prints content of book1.es_ES.txt deserialized from the snapshot. {#prints-content-of-book1es_estxt-deserialized-from-the-snapshot}

Actualmente, la aplicación deserializada de una instantánea del espacio de usuario no se puede volver a tomar una instantánea, por lo que estas API solo están disponibles para las aplicaciones que no se deserializan de una instantánea del espacio de usuario.

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

Agregado en: v18.6.0, v16.17.0

  • callback <Function> Callback que se invocará antes de la serialización.
  • data <any> Datos opcionales que se pasarán al callback cuando se llame.

Agregue un callback que se llamará cuando la instancia de Node.js esté a punto de serializarse en una instantánea y salir. Esto se puede usar para liberar recursos que no deberían o no pueden serializarse o para convertir los datos del usuario en una forma más adecuada para la serialización.

Los callbacks se ejecutan en el orden en que se agregan.

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

Agregado en: v18.6.0, v16.17.0

  • callback <Function> Callback que se invocará después de deserializar la instantánea.
  • data <any> Datos opcionales que se pasarán al callback cuando se llame.

Agregue un callback que se llamará cuando la instancia de Node.js se deserialice desde una instantánea. El callback y los data (si se proporcionan) se serializarán en la instantánea, se pueden usar para reinicializar el estado de la aplicación o para volver a adquirir los recursos que la aplicación necesita cuando la aplicación se reinicia desde la instantánea.

Los callbacks se ejecutan en el orden en que se agregan.

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

Agregado en: v18.6.0, v16.17.0

  • callback <Function> Callback que se invocará como el punto de entrada después de que se deserialice la instantánea.
  • data <any> Datos opcionales que se pasarán al callback cuando se llame.

Esto establece el punto de entrada de la aplicación Node.js cuando se deserializa desde una instantánea. Esto se puede llamar solo una vez en el script de construcción de instantáneas. Si se llama, la aplicación deserializada ya no necesita un script de punto de entrada adicional para iniciarse y simplemente invocará el callback junto con los datos deserializados (si se proporcionan), de lo contrario, aún debe proporcionarse un script de punto de entrada a la aplicación deserializada.

v8.startupSnapshot.isBuildingSnapshot()

Agregada en: v18.6.0, v16.17.0

Devuelve true si la instancia de Node.js se está ejecutando para construir una instantánea.

Clase: v8.GCProfiler

Agregada en: v19.6.0, v18.15.0

Esta API recopila datos de GC en el hilo actual.

new v8.GCProfiler()

Agregada en: v19.6.0, v18.15.0

Crea una nueva instancia de la clase v8.GCProfiler.

profiler.start()

Agregada en: v19.6.0, v18.15.0

Comienza a recopilar datos de GC.

profiler.stop()

Agregada en: v19.6.0, v18.15.0

Deja de recopilar datos de GC y devuelve un objeto. El contenido del objeto es el siguiente.

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
}

Aquí hay un ejemplo.

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