V8
Código fuente: lib/v8.js
El módulo node:v8
expone las API que son específicas de la versión de V8 integrada en el binario de Node.js. Se puede acceder a él usando:
const v8 = require('node:v8')
v8.cachedDataVersionTag()
Añadido en: v8.0.0
- Devuelve: <entero>
Devuelve un entero que representa una etiqueta de versión derivada de la versión de V8, las banderas de línea de comandos y las características de CPU detectadas. Esto es útil para determinar si un búfer cachedData
de vm.Script
es compatible con esta instancia de V8.
console.log(v8.cachedDataVersionTag()) // 3947234607
// El valor devuelto por v8.cachedDataVersionTag() se deriva de la versión de V8,
// las banderas de la línea de comandos y las características de la CPU detectadas.
// Comprueba que el valor se actualice cuando se cambian las banderas.
v8.setFlagsFromString('--allow_natives_syntax')
console.log(v8.cachedDataVersionTag()) // 183726201
v8.getHeapCodeStatistics()
Agregado en: v12.8.0
- Devuelve: <Objeto>
Obtiene estadísticas sobre el código y sus metadatos en el heap, consulta la API V8 GetHeapCodeAndMetadataStatistics
. Devuelve un objeto con las siguientes propiedades:
code_and_metadata_size
<número>bytecode_and_metadata_size
<número>external_script_source_size
<número>cpu_profiler_metadata_size
<número>
{
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ón | Cambios |
---|---|
v19.1.0 | Soporte para opciones para configurar la instantánea del montón. |
v11.13.0 | Añadido en: v11.13.0 |
options
<Object>Devuelve: <stream.Readable> Un Readable que contiene la instantánea del montón V8.
Genera una instantánea del montón V8 actual y devuelve un Stream Readable que puede usarse para leer la representación serializada en JSON. Este formato de stream JSON está pensado para usarse 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.
La creación de una instantánea del montón requiere una memoria aproximadamente el doble del tamaño del montón en el momento en que se crea la instantánea. Esto genera el riesgo de que los eliminadores OOM terminen el proceso.
La generación de una instantánea es una operación síncrona que bloquea el bucle de eventos durante un período que depende del tamaño del montón.
// Imprimir la instantánea del montón en la consola
const v8 = require('node:v8')
const stream = v8.getHeapSnapshot()
stream.pipe(process.stdout)
v8.getHeapSpaceStatistics()
[Historial]
Versión | Cambios |
---|---|
v7.5.0 | Soporte para valores que exceden el rango de enteros sin signo de 32 bits. |
v6.0.0 | Añadido en: v6.0.0 |
- Devuelve: <Object[]>
Devuelve estadísticas sobre los espacios de memoria heap de V8, es decir, los segmentos que componen el heap de V8. No se puede garantizar ni el orden de los espacios de memoria heap ni la disponibilidad de un espacio de memoria heap, ya que las estadísticas se proporcionan a través de la función GetHeapSpaceStatistics
de V8 y pueden cambiar de una versión de V8 a otra.
El valor devuelto es un array de objetos que contiene las siguientes propiedades:
space_name
<string>space_size
<number>space_used_size
<number>space_available_size
<number>physical_space_size
<number>
[
{
"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ón | Cambios |
---|---|
v7.5.0 | Soporte para valores que exceden el rango de enteros sin signo de 32 bits. |
v7.2.0 | Se agregaron malloced_memory , peak_malloced_memory y does_zap_garbage . |
v1.0.0 | Agregado en: v1.0.0 |
- Devuelve: <Object>
Devuelve un objeto con las siguientes propiedades:
total_heap_size
<number>total_heap_size_executable
<number>total_physical_size
<number>total_available_size
<number>used_heap_size
<number>heap_size_limit
<number>malloced_memory
<number>peak_malloced_memory
<number>does_zap_garbage
<number>number_of_native_contexts
<number>number_of_detached_contexts
<number>total_global_handles_size
<number>used_global_handles_size
<number>external_memory
<number>
total_heap_size
El valor de total_heap_size es el número de bytes que V8 ha asignado para el montón. Esto puede crecer si used_heap necesita más memoria.
total_heap_size_executable
El valor de total_heap_size_executable es la parte del montón que puede contener código ejecutable, en bytes. Esto incluye la memoria utilizada por el código compilado por 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 montón de V8, en bytes. Esta es la cantidad de memoria que se confirma (o está en uso) en lugar de reservarse.
total_available_size
El valor de total_available_size es el número de bytes de memoria disponible para el montón de V8. Este valor representa cuánta más memoria puede usar V8 antes de exceder el límite del montón.
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 montón 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 de 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 desprendieron y aún no se han recogido 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 manejadores globales de V8.
used_global_handles_size
El valor de used_global_handles_size es el tamaño de memoria utilizado de los manejadores globales de V8.
external_memory
El valor de external_memory es el tamaño de memoria de los búferes de matriz y las cadenas externas.
{
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])
Añadido en: v22.0.0, v20.13.0
[Estable: 1 - Experimental]
Estable: 1 Estabilidad: 1.1 - Desarrollo activo
ctor
<Function> El constructor que puede ser usado para buscar en la cadena de prototipos con el fin de filtrar los objetos objetivo en el heap.options
<undefined> | <Object>format
<string> Si es'count'
, se retorna el conteo de objetos encontrados. Si es'summary'
, se retorna un array con cadenas de resumen de los objetos encontrados.
Retorna: {number|Array
Esto es similar a la API de consola queryObjects()
proporcionada por la consola de Chromium DevTools. Puede ser usada para buscar objetos que tienen el constructor coincidente en su cadena de prototipos en el heap después de una recolección de basura completa, lo que puede ser útil para 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 retorna referencias sin procesar a los objetos encontrados. Por defecto, retorna el conteo de objetos encontrados. Si options.format
es 'summary'
, retorna un array conteniendo representaciones de cadena breves para cada objeto. La visibilidad proporcionada en esta API es similar a la que proporciona la instantánea del heap, mientras que los usuarios pueden ahorrar el costo de serialización y 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.
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 que, cuando hay clases hijas que heredan de un constructor,
// el constructor también aparece en la cadena de prototipos del prototipo
// de las clases hijas, por lo que el prototipo de las clases hijas también se
// incluiría en el resultado.
console.log(queryObjects(A)) // 3
// [ "B { foo: 'bar', bar: 'qux' }", 'A {}', "A { foo: 'bar' }" ]
console.log(queryObjects(A, { format: 'summary' }))
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 que, cuando hay clases hijas que heredan de un constructor,
// el constructor también aparece en la cadena de prototipos del prototipo
// de las clases hijas, por lo que el prototipo de las clases hijas también se
// incluiría en el resultado.
console.log(queryObjects(A)) // 3
// [ "B { foo: 'bar', bar: 'qux' }", 'A {}', "A { foo: 'bar' }" ]
console.log(queryObjects(A, { format: 'summary' }))
v8.setFlagsFromString(flags)
Agregado en: v1.0.0
flags
<string>
El método v8.setFlagsFromString()
se puede usar para establecer programáticamente las banderas de línea de comandos de V8. Este método debe usarse con cuidado. Cambiar la configuración después de que la VM se haya iniciado puede resultar en un comportamiento impredecible, incluyendo bloqueos y pérdida de datos; o simplemente puede no hacer nada.
Las opciones de V8 disponibles para una versión de Node.js se pueden determinar ejecutando node --v8-options
.
Uso:
// 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()
Agregado en: v15.1.0, v14.18.0, v12.22.0
El método v8.stopCoverage()
permite al usuario detener la colección de cobertura iniciada por NODE_V8_COVERAGE
, para que V8 pueda liberar los registros de conteo de ejecución y optimizar el código. Esto se puede usar junto con v8.takeCoverage()
si el usuario quiere recolectar la cobertura bajo demanda.
v8.takeCoverage()
Agregado 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 puede ser invocado varias veces durante la vida del proceso. Cada vez, el contador de ejecución se restablecerá y se escribirá un nuevo informe de cobertura en el directorio especificado por NODE_V8_COVERAGE
.
Cuando el proceso está a punto de salir, 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ón | Cambios |
---|---|
v19.1.0 | Soporte para opciones para configurar la instantánea de montón. |
v18.0.0 | Ahora se lanzará una excepción si no se pudo escribir el archivo. |
v18.0.0 | Hacer que los códigos de error devueltos sean consistentes en todas las plataformas. |
v11.13.0 | Agregado en: v11.13.0 |
filename
<string> La ruta de archivo donde se guardará la instantánea de 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 awriteHeapSnapshot()
desde el hilo principal de Node.js o el ID de un hilo de trabajo.options
<Object>Devuelve: <string> El nombre de archivo donde se guardó la instantánea.
Genera una instantánea del montón de 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 aislado 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 una memoria aproximadamente dos veces el 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.
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(`volcado de montón del trabajador: ${filename}`)
// Ahora obtener un volcado de montón para el hilo principal.
console.log(`volcado de montón del hilo principal: ${writeHeapSnapshot()}`)
})
// Decir al trabajador que cree un volcado de montón.
worker.postMessage('heapdump')
} else {
parentPort.once('message', message => {
if (message === 'heapdump') {
// Generar un volcado de montón para el trabajador
// y devolver el nombre de archivo al padre.
parentPort.postMessage(writeHeapSnapshot())
}
})
}
v8.setHeapSnapshotNearHeapLimit(limit)
Añadido en: v18.10.0, v16.18.0
[Estable: 1 - Experimental]
Estable: 1 Estabilidad: 1 - Experimental
limit
<integer>
La API no realiza ninguna operación si --heapsnapshot-near-heap-limit
ya se ha establecido desde la línea de comandos o si se llama a la API más de una vez. limit
debe ser un entero positivo. Consulta --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 guardar en disco). Los valores de JavaScript iguales pueden dar como resultado una salida serializada diferente.
v8.serialize(value)
Agregado en: v8.0.0
Utiliza un DefaultSerializer
para serializar value
en un búfer.
Se lanzará ERR_BUFFER_TOO_LARGE
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
buffer
<Buffer> | <TypedArray> | <DataView> Un búfer devuelto porserialize()
.
Utiliza un DefaultDeserializer
con opciones predeterminadas para leer un valor JS desde 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)
value
<any>
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: <Buffer>
Devuelve el búfer interno almacenado. Este serializador no debe utilizarse 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)
id
<integer> Un entero sin signo de 32 bits.arrayBuffer
<ArrayBuffer> Una instancia deArrayBuffer
.
Marca un ArrayBuffer
como si su contenido se hubiera transferido fuera de banda. Pase el ArrayBuffer
correspondiente en el contexto de deserialización a deserializer.transferArrayBuffer()
.
serializer.writeUint32(value)
value
<entero>
Escribe un entero sin signo de 32 bits sin formato. Para uso dentro de un serializer._writeHostObject()
personalizado.
serializer.writeUint64(hi, lo)
Escribe un entero sin signo de 64 bits sin formato, dividido en partes de 32 bits alta y baja. Para uso dentro de un serializer._writeHostObject()
personalizado.
serializer.writeDouble(value)
value
<número>
Escribe un valor number
de JS. Para uso dentro de un serializer._writeHostObject()
personalizado.
serializer.writeRawBytes(buffer)
buffer
<Buffer> | <TypedArray> | <DataView>
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)
object
<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 generar una excepción adecuada.
Este método no está presente en la propia clase Serializer
, pero puede ser proporcionado por subclases.
serializer._getDataCloneError(message)
message
<string>
Este método se llama para generar objetos de error que se generarán cuando un objeto no se pueda clonar.
Este método tiene como valor predeterminado el constructor Error
y se puede sobrescribir en las subclases.
serializer._getSharedArrayBufferId(sharedArrayBuffer)
sharedArrayBuffer
<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, usando el mismo ID si este SharedArrayBuffer
ya ha sido serializado. Al deserializar, este ID se pasará a deserializer.transferArrayBuffer()
.
Si el objeto no puede ser serializado, se debe lanzar una excepción.
Este método no está presente en la clase Serializer
en sí, pero puede ser proporcionado por las subclases.
serializer._setTreatArrayBufferViewsAsHostObjects(flag)
flag
<boolean> Predeterminado:false
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)
buffer
<Buffer> | <TypedArray> | <DataView> Un búfer devuelto porserializer.releaseBuffer()
.
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 cable no válido o no compatible. En ese caso, se genera un Error
.
deserializer.readValue()
Deserializa un valor de JavaScript del búfer y lo devuelve.
deserializer.transferArrayBuffer(id, arrayBuffer)
id
<integer> Un entero sin signo de 32 bits.arrayBuffer
<ArrayBuffer> | <SharedArrayBuffer> Una instancia deArrayBuffer
.
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 SharedArrayBuffer
s).
deserializer.getWireFormatVersion()
- Devuelve: <integer>
Lee la versión del formato de cable subyacente. Es probable que sea útil principalmente para el código heredado que lee versiones antiguas del formato de cable. Puede que no se llame antes de .readHeader()
.
deserializer.readUint32()
- Devuelve: <integer>
Lee un entero sin signo sin procesar de 32 bits y lo devuelve. Para usar dentro de un deserializer._readHostObject()
personalizado.
deserializer.readUint64()
- Devuelve: <integer[]>
Lee un entero sin signo sin procesar de 64 bits y lo devuelve como una matriz [hi, lo]
con dos entradas de enteros sin signo de 32 bits. Para usar dentro de un deserializer._readHostObject()
personalizado.
deserializer.readDouble()
- Devuelve: <number>
Lee un valor number
de JS. Para usar dentro de un deserializer._readHostObject()
personalizado.
deserializer.readRawBytes(length)
Lee bytes sin procesar 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()
Se llama a este método para leer algún tipo de objeto host, es decir, un objeto que se crea mediante enlaces nativos de C++. Si no es posible deserializar los datos, se debe generar una excepción adecuada.
Este método no está presente en la clase Deserializer
en sí, pero puede ser proporcionado por las 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
Añadido en: v8.0.0
Una subclase de Deserializer
correspondiente al formato escrito por DefaultSerializer
.
Ganchos de Promesas
La interfaz promiseHooks
se puede usar para rastrear eventos del ciclo de vida de las promesas. Para rastrear toda la actividad asíncrona, vea async_hooks
que internamente usa este módulo para producir eventos del ciclo de vida de las promesas además de eventos para otros recursos asíncronos. Para la gestión del contexto de la solicitud, vea AsyncLocalStorage
.
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
// `then()` o `catch()`. También sucede cuando se llama a una función async o
// se 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` sucede cuando una promesa recibe una resolución o
// un valor de rechazo. Esto puede suceder de forma síncrona, como cuando se usa
// `Promise.resolve()` en una entrada que no es una 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()`
// o se reanude la ejecución de un `await`.
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 reanudarse desde otro.
function after(promise) {
console.log('una promesa terminó de llamar a un controlador then', { promise })
}
// Los ganchos 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 se pueden iniciar y detener en grupos
const stopHookSet = promiseHooks.createHook({
init,
settled,
before,
after,
})
// Para detener un gancho, 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
init
<Function> La función de retrollamadainit
que se debe llamar cuando se crea una promesa.- Devuelve: <Function> Llamar para detener el gancho.
El gancho init
debe ser una función simple. Proporcionar una función asíncrona lanzará un error, ya que produciría un bucle de microtareas infinito.
import { promiseHooks } from 'node:v8'
const stop = promiseHooks.onInit((promise, parent) => {})
const { promiseHooks } = require('node:v8')
const stop = promiseHooks.onInit((promise, parent) => {})
promiseHooks.onSettled(settled)
Agregado en: v17.1.0, v16.14.0
settled
<Function> La función de retrollamadasettled
que se debe llamar cuando una promesa se resuelve o se rechaza.- Devuelve: <Function> Llamar para detener el gancho.
El gancho settled
debe ser una función simple. Proporcionar una función asíncrona lanzará un error, ya que produciría un bucle de microtareas infinito.
import { promiseHooks } from 'node:v8'
const stop = promiseHooks.onSettled(promise => {})
const { promiseHooks } = require('node:v8')
const stop = promiseHooks.onSettled(promise => {})
promiseHooks.onBefore(before)
Agregado en: v17.1.0, v16.14.0
before
<Función> La retrollamadabefore
para llamar antes de que se ejecute una continuación de la promesa.- Devuelve: <Función> Llamar para detener el gancho.
El gancho before
debe ser una función simple. Proporcionar una función async arrojará un error ya que produciría un bucle infinito de microtareas.
import { promiseHooks } from 'node:v8'
const stop = promiseHooks.onBefore(promise => {})
const { promiseHooks } = require('node:v8')
const stop = promiseHooks.onBefore(promise => {})
promiseHooks.onAfter(after)
Agregado en: v17.1.0, v16.14.0
after
<Función> La retrollamadaafter
para llamar después de que se ejecute una continuación de la promesa.- Devuelve: <Función> Llamar para detener el gancho.
El gancho after
debe ser una función simple. Proporcionar una función async arrojará un error ya que produciría un bucle infinito de microtareas.
import { promiseHooks } from 'node:v8'
const stop = promiseHooks.onAfter(promise => {})
const { promiseHooks } = require('node:v8')
const stop = promiseHooks.onAfter(promise => {})
promiseHooks.createHook(callbacks)
Añadido en: v17.1.0, v16.14.0
callbacks
<Object> Las Funciones de retorno de Hook para registrarinit
<Function> La función de retornoinit
.before
<Function> La función de retornobefore
.after
<Function> La función de retornoafter
.settled
<Function> La función de retornosettled
.
Devuelve: <Function> Se utiliza para deshabilitar los hooks
Las funciones de retorno del hook deben ser funciones simples. Proporcionar funciones asíncronas provocará un error, ya que produciría un bucle de microtareas infinito.
Registra las funciones que se llamarán para diferentes eventos del ciclo de vida de cada promesa.
Las funciones de retorno init()
/before()
/after()
/settled()
se llaman para los eventos respectivos durante el ciclo de vida de una promesa.
Todas las funciones de retorno son opcionales. Por ejemplo, si solo es necesario realizar un seguimiento de la creación de promesas, solo es necesario pasar la función de retorno init
. Los detalles de todas las funciones que se pueden pasar a callbacks
se encuentran en la sección Funciones de retorno de Hook.
import { promiseHooks } from 'node:v8'
const stopAll = promiseHooks.createHook({
init(promise, parent) {},
})
const { promiseHooks } = require('node:v8')
const stopAll = promiseHooks.createHook({
init(promise, parent) {},
})
Hook callbacks
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 se 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 archivos que tienen un estado "cerrado" distinto para expresar el evento del ciclo de vida destroy
, mientras que las promesas siguen siendo utilizables siempre que el código aún pueda alcanzarlas. El seguimiento de la recolección de basura se utiliza para que las promesas encajen en el modelo de eventos de async_hooks
, sin embargo, este seguimiento es muy costoso y es posible que nunca se recolecten como basura.
Dado que las promesas son recursos asíncronos cuyo ciclo de vida se rastrea a través del mecanismo de hooks de promesas, las devoluciones de llamada init()
, before()
, after()
y settled()
no deben ser funciones asíncronas, ya que crean más promesas que producirían un bucle infinito.
Si bien esta API se utiliza para introducir eventos de promesas en async_hooks
, el orden entre los dos no está definido. Ambas API son multi-inquilino y, por lo tanto, podrían producir eventos en cualquier orden relativo entre sí.
init(promise, parent)
promise
<Promise> La promesa que se está creando.parent
<Promise> La promesa de la que se continúa, si corresponde.
Se llama cuando se construye una promesa. Esto no significa que ocurrirán los eventos before
/after
correspondientes, solo que existe la posibilidad. Esto sucederá si se crea una promesa sin obtener nunca una continuación.
before(promise)
promise
<Promise>
Se llama antes de que se ejecute una continuación de promesa. Esto puede ser en la forma de controladores then()
, catch()
o finally()
o un await
reanudándose.
La devolución de llamada before
se llamará de 0 a N veces. La devolución de llamada before
se llamará normalmente 0 veces si nunca se realizó ninguna continuación para la promesa. La devolución de llamada before
puede llamarse muchas veces en el caso de que se hayan realizado muchas continuaciones a partir de la misma promesa.
after(promise)
promise
<Promise>
Se llama inmediatamente después de que se ejecuta una continuación de promesa. Esto puede ser después de un manejador then()
, catch()
o finally()
o antes de un await
después de otro await
.
settled(promise)
promise
<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
Añadido en: v18.6.0, v16.17.0
[Estable: 1 - Experimental]
Estable: 1 Estabilidad: 1 - Experimental
La interfaz v8.startupSnapshot
se puede usar para añadir hooks de serialización y deserialización para instantáneas de inicio personalizadas.
$ node --snapshot-blob snapshot.blob --build-snapshot entry.js
# Esto lanza un proceso con la instantánea {#this-launches-a-process-with-the-snapshot}
$ node --snapshot-blob snapshot.blob
En el ejemplo de arriba, 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 se puede usar la información para sincronizar estos objetos durante la deserialización de la instantánea. Por ejemplo, si entry.js
contiene el siguiente script:
'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()
// Leyendo una serie de archivos de un directorio y guardándolos en 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 aquí es donde se coloca el script de la instantánea
// durante el tiempo de creación de la instantánea.
const shelf = new BookShelf(__dirname, ['book1.en_US.txt', 'book1.es_ES.txt', 'book2.zh_CN.txt'])
assert(v8.startupSnapshot.isBuildingSnapshot())
// En la serialización de la instantánea, comprime los libros para reducir el tamaño.
v8.startupSnapshot.addSerializeCallback(BookShelf.compressAll, shelf)
// En la deserialización de la instantánea, descomprime los libros.
v8.startupSnapshot.addDeserializeCallback(BookShelf.decompressAll, shelf)
v8.startupSnapshot.setDeserializeMainFunction(shelf => {
// process.env y process.argv se actualizan durante la instantánea
// deserialización.
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, usando process.env
y process.argv
actualizados del proceso lanzado:
$ BOOK_LANG=es_ES node --snapshot-blob snapshot.blob book1
# Imprime el contenido de book1.es_ES.txt deserializado de la instantánea. {#prints-content-of-book1es_estxt-deserialized-from-the-snapshot}
Actualmente, la aplicación deserializada de una instantánea de usuario no se puede volver a instantanear, por lo que estas API solo están disponibles para aplicaciones que no se deserializan de una instantánea 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 a lacallback
cuando se llame.
Agrega una callback que se llamará cuando la instancia de Node.js esté a punto de ser serializada en una instantánea y salir. Esto se puede usar para liberar recursos que no deben o no pueden ser serializados o para convertir los datos del usuario en una forma más adecuada para la serialización.
Las 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 que se deserialice la instantánea.data
<any> Datos opcionales que se pasarán a lacallback
cuando se llame.
Agrega una callback que se llamará cuando la instancia de Node.js se deserialice de una instantánea. La 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.
Las 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 punto de entrada después de que se deserialice la instantánea.data
<any> Datos opcionales que se pasarán a lacallback
cuando se llame.
Esto establece el punto de entrada de la aplicación Node.js cuando se deserializa desde una instantánea. Esto solo se puede llamar una vez en el script de construcción de la instantánea. Si se llama, la aplicación deserializada ya no necesita un script de punto de entrada adicional para iniciarse y simplemente invocará la callback junto con los datos deserializados (si se proporcionan), de lo contrario, todavía se debe proporcionar un script de punto de entrada a la aplicación deserializada.
v8.startupSnapshot.isBuildingSnapshot()
Agregado en: v18.6.0, v16.17.0
- Devuelve: <boolean>
Devuelve verdadero si la instancia de Node.js se ejecuta para construir una instantánea.
Clase: v8.GCProfiler
Agregado en: v19.6.0, v18.15.0
Esta API recopila datos de GC en el hilo actual.
new v8.GCProfiler()
Agregado en: v19.6.0, v18.15.0
Crea una nueva instancia de la clase v8.GCProfiler
.
profiler.start()
Agregado en: v19.6.0, v18.15.0
Comienza a recopilar datos de GC.
profiler.stop()
Agregado en: v19.6.0, v18.15.0
Detiene la recopilación de datos de GC y devuelve un objeto. El contenido del objeto es el siguiente.
{
"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.
const { GCProfiler } = require('node:v8')
const profiler = new GCProfiler()
profiler.start()
setTimeout(() => {
console.log(profiler.stop())
}, 1000)