V8
Codice Sorgente: lib/v8.js
Il modulo node:v8
espone API specifiche alla versione di V8 integrata nel binary di Node.js. È accessibile tramite:
const v8 = require('node:v8')
v8.cachedDataVersionTag()
Aggiunto in: v8.0.0
- Restituisce: <integer>
Restituisce un intero che rappresenta un tag di versione derivato dalla versione di V8, dai flag della riga di comando e dalle funzionalità della CPU rilevate. Questo è utile per determinare se un buffer cachedData
di vm.Script
è compatibile con questa istanza di V8.
console.log(v8.cachedDataVersionTag()) // 3947234607
// Il valore restituito da v8.cachedDataVersionTag() è derivato dalla versione di V8,
// dai flag della riga di comando e dalle funzionalità della CPU rilevate. Testare che il valore
// venga effettivamente aggiornato quando i flag vengono modificati.
v8.setFlagsFromString('--allow_natives_syntax')
console.log(v8.cachedDataVersionTag()) // 183726201
v8.getHeapCodeStatistics()
Aggiunto in: v12.8.0
- Restituisce: <Object>
Ottiene le statistiche sul codice e sui suoi metadati nell'heap, vedi l'API V8 GetHeapCodeAndMetadataStatistics
. Restituisce un oggetto con le seguenti proprietà:
code_and_metadata_size
<number>bytecode_and_metadata_size
<number>external_script_source_size
<number>cpu_profiler_metadata_size
<number>
{
code_and_metadata_size: 212208,
bytecode_and_metadata_size: 161368,
external_script_source_size: 1410794,
cpu_profiler_metadata_size: 0,
}
v8.getHeapSnapshot([options])
[Cronologia]
Versione | Modifiche |
---|---|
v19.1.0 | Supporto opzioni per configurare lo snapshot dell'heap. |
v11.13.0 | Aggiunto in: v11.13.0 |
options
<Oggetto>exposeInternals
<booleano> Se vero, espone gli interni nello snapshot dell'heap. Predefinito:false
.exposeNumericValues
<booleano> Se vero, espone i valori numerici in campi artificiali. Predefinito:false
.
Restituisce: <stream.Readable> Un flusso leggibile contenente lo snapshot dell'heap V8.
Genera uno snapshot dell'heap V8 corrente e restituisce un flusso leggibile che può essere utilizzato per leggere la rappresentazione serializzata JSON. Questo formato di flusso JSON è destinato all'uso con strumenti come Chrome DevTools. Lo schema JSON non è documentato ed è specifico del motore V8. Pertanto, lo schema potrebbe cambiare da una versione di V8 all'altra.
La creazione di uno snapshot dell'heap richiede una memoria circa doppia rispetto alle dimensioni dell'heap al momento della creazione dello snapshot. Ciò comporta il rischio che i killer OOM terminino il processo.
La generazione di uno snapshot è un'operazione sincrona che blocca il ciclo degli eventi per una durata che dipende dalle dimensioni dell'heap.
// Stampa lo snapshot dell'heap sulla console
const v8 = require('node:v8')
const stream = v8.getHeapSnapshot()
stream.pipe(process.stdout)
v8.getHeapSpaceStatistics()
[Cronologia]
Versione | Modifiche |
---|---|
v7.5.0 | Supporto valori che superano l'intervallo di numeri interi senza segno a 32 bit. |
v6.0.0 | Aggiunto in: v6.0.0 |
- Restituisce: <Oggetto[]>
Restituisce le statistiche sugli spazi heap V8, ovvero i segmenti che compongono l'heap V8. Né l'ordinamento degli spazi heap, né la disponibilità di uno spazio heap possono essere garantite poiché le statistiche sono fornite tramite la funzione V8 GetHeapSpaceStatistics
e possono cambiare da una versione V8 all'altra.
Il valore restituito è una matrice di oggetti contenenti le seguenti proprietà:
space_name
<stringa>space_size
<numero>space_used_size
<numero>space_available_size
<numero>physical_space_size
<numero>
[
{
"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()
[Cronologia]
Versione | Modifiche |
---|---|
v7.5.0 | Supporto di valori che superano l'intervallo di interi senza segno a 32 bit. |
v7.2.0 | Aggiunti malloced_memory , peak_malloced_memory , e does_zap_garbage . |
v1.0.0 | Aggiunto in: v1.0.0 |
- Restituisce: <Oggetto>
Restituisce un oggetto con le seguenti proprietà:
total_heap_size
<numero>total_heap_size_executable
<numero>total_physical_size
<numero>total_available_size
<numero>used_heap_size
<numero>heap_size_limit
<numero>malloced_memory
<numero>peak_malloced_memory
<numero>does_zap_garbage
<numero>number_of_native_contexts
<numero>number_of_detached_contexts
<numero>total_global_handles_size
<numero>used_global_handles_size
<numero>external_memory
<numero>
total_heap_size
Il valore di total_heap_size
è il numero di byte che V8 ha allocato per l'heap. Questo può crescere se used_heap
necessita di più memoria.
total_heap_size_executable
Il valore di total_heap_size_executable
è la porzione dell'heap che può contenere codice eseguibile, in byte. Questo include la memoria utilizzata dal codice compilato JIT e qualsiasi memoria che deve essere mantenuta eseguibile.
total_physical_size
Il valore di total_physical_size
è la memoria fisica effettivamente utilizzata dall'heap V8, in byte. Questa è la quantità di memoria che è impegnata (o in uso) piuttosto che riservata.
total_available_size
Il valore di total_available_size
è il numero di byte di memoria disponibili per l'heap V8. Questo valore rappresenta quanta altra memoria V8 può utilizzare prima di superare il limite dell'heap.
used_heap_size
Il valore di used_heap_size
è il numero di byte attualmente utilizzati dagli oggetti JavaScript di V8. Questa è la memoria effettivamente in uso e non include la memoria che è stata allocata ma non ancora utilizzata.
heap_size_limit
Il valore di heap_size_limit
è la dimensione massima dell'heap V8, in byte (o il limite predefinito, determinato dalle risorse di sistema, o il valore passato all'opzione --max_old_space_size
).
malloced_memory
Il valore di malloced_memory
è il numero di byte allocati tramite malloc
da V8.
peak_malloced_memory
Il valore di peak_malloced_memory
è il numero massimo di byte allocati tramite malloc
da V8 durante la durata del processo.
does_zap_garbage
è un booleano 0/1, che indica se l'opzione --zap_code_space
è abilitata o meno. Questo fa sì che V8 sovrascriva i garbage dell'heap con un pattern di bit. L'impronta RSS (resident set size) diventa più grande perché tocca continuamente tutte le pagine dell'heap e questo le rende meno inclini a essere scambiate dal sistema operativo.
number_of_native_contexts
Il valore di native_context
è il numero di contesti di livello superiore attualmente attivi. L'aumento di questo numero nel tempo indica una perdita di memoria.
number_of_detached_contexts
Il valore di detached_context
è il numero di contesti che sono stati distaccati e non ancora raccolti come garbage. Questo numero diverso da zero indica una potenziale perdita di memoria.
total_global_handles_size
Il valore di total_global_handles_size
è la dimensione totale di memoria degli handle globali V8.
used_global_handles_size
Il valore di used_global_handles_size
è la dimensione di memoria utilizzata dagli handle globali V8.
external_memory
Il valore di external_memory
è la dimensione di memoria degli array buffer e delle stringhe esterne.
{
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])
Aggiunto in: v22.0.0, v20.13.0
[Stabile: 1 - Sperimentale]
Stabile: 1 Stabilità: 1.1 - Sviluppo attivo
ctor
<Function> Il costruttore che può essere utilizzato per cercare nella catena dei prototipi al fine di filtrare gli oggetti di destinazione nell'heap.options
<undefined> | <Object>format
<string> Se è'count'
, viene restituito il conteggio degli oggetti corrispondenti. Se è'summary'
, viene restituita una matrice con stringhe riepilogative degli oggetti corrispondenti.
Restituisce: {number|Array
Questa funzione è simile all'API della console queryObjects()
fornita dalla console di Chromium DevTools. Può essere utilizzata per cercare oggetti che hanno il costruttore corrispondente nella loro catena di prototipi nell'heap dopo un'accurata garbage collection, il che può essere utile per i test di regressione delle perdite di memoria. Per evitare risultati sorprendenti, gli utenti dovrebbero evitare di utilizzare questa API su costruttori di cui non controllano l'implementazione, o su costruttori che possono essere invocati da altre parti dell'applicazione.
Per evitare perdite accidentali, questa API non restituisce riferimenti grezzi agli oggetti trovati. Per impostazione predefinita, restituisce il conteggio degli oggetti trovati. Se options.format
è 'summary'
, restituisce una matrice contenente brevi rappresentazioni di stringa per ciascun oggetto. La visibilità fornita in questa API è simile a quella fornita dallo snapshot dell'heap, mentre gli utenti possono risparmiare il costo di serializzazione e analisi e filtrare direttamente gli oggetti di destinazione durante la ricerca.
Solo gli oggetti creati nel contesto di esecuzione corrente sono inclusi nei risultati.
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' }))
// Si noti che, quando ci sono classi figlio che ereditano da un costruttore,
// il costruttore appare anche nella catena dei prototipi del prototipo delle classi figlio,
// quindi il prototipo delle classi figlio sarebbe incluso anche nel risultato.
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' }))
// Si noti che, quando ci sono classi figlio che ereditano da un costruttore,
// il costruttore appare anche nella catena dei prototipi del prototipo delle classi figlio,
// quindi il prototipo delle classi figlio sarebbe incluso anche nel risultato.
console.log(queryObjects(A)) // 3
// [ "B { foo: 'bar', bar: 'qux' }", 'A {}', "A { foo: 'bar' }" ]
console.log(queryObjects(A, { format: 'summary' }))
v8.setFlagsFromString(flags)
Aggiunto in: v1.0.0
flags
<string>
Il metodo v8.setFlagsFromString()
può essere utilizzato per impostare programmaticamente i flag della riga di comando di V8. Questo metodo dovrebbe essere usato con cautela. La modifica delle impostazioni dopo l'avvio della VM può comportare comportamenti imprevedibili, inclusi arresti anomali e perdita di dati; oppure potrebbe semplicemente non fare nulla.
Le opzioni V8 disponibili per una versione di Node.js possono essere determinate eseguendo node --v8-options
.
Utilizzo:
// Stampa gli eventi GC su stdout per un minuto.
const v8 = require('node:v8')
v8.setFlagsFromString('--trace_gc')
setTimeout(() => {
v8.setFlagsFromString('--notrace_gc')
}, 60e3)
v8.stopCoverage()
Aggiunto in: v15.1.0, v14.18.0, v12.22.0
Il metodo v8.stopCoverage()
consente all'utente di interrompere la raccolta della copertura avviata da NODE_V8_COVERAGE
, in modo che V8 possa rilasciare i record del conteggio delle esecuzioni e ottimizzare il codice. Questo può essere utilizzato in congiunzione con v8.takeCoverage()
se l'utente desidera raccogliere la copertura su richiesta.
v8.takeCoverage()
Aggiunto in: v15.1.0, v14.18.0, v12.22.0
Il metodo v8.takeCoverage()
consente all'utente di scrivere su disco la copertura avviata da NODE_V8_COVERAGE
su richiesta. Questo metodo può essere richiamato più volte durante la vita del processo. Ogni volta il contatore di esecuzione verrà ripristinato e un nuovo report di copertura verrà scritto nella directory specificata da NODE_V8_COVERAGE
.
Quando il processo sta per terminare, una copertura finale verrà comunque scritta su disco a meno che v8.stopCoverage()
non venga richiamato prima che il processo termini.
v8.writeHeapSnapshot([filename[,options]])
[Cronologia]
Versione | Modifiche |
---|---|
v19.1.0 | Supporto opzioni per configurare lo snapshot dell'heap. |
v18.0.0 | Ora verrà sollevata un'eccezione se il file non potesse essere scritto. |
v18.0.0 | Rendi i codici di errore restituiti coerenti su tutte le piattaforme. |
v11.13.0 | Aggiunto in: v11.13.0 |
filename
<string> Il percorso del file in cui deve essere salvato lo snapshot dell'heap V8. Se non specificato, verrà generato un nome file con il modello'Heap-${yyyymmdd}-${hhmmss}-${pid}-${thread_id}.heapsnapshot'
, dove{pid}
sarà il PID del processo Node.js,{thread_id}
sarà0
quandowriteHeapSnapshot()
viene chiamato dal thread principale di Node.js o l'ID di un thread worker.options
<Object>Restituisce: <string> Il nome del file in cui è stato salvato lo snapshot.
Genera uno snapshot dell'heap V8 corrente e lo scrive in un file JSON. Questo file è destinato all'utilizzo con strumenti come Chrome DevTools. Lo schema JSON non è documentato ed è specifico del motore V8 e potrebbe cambiare da una versione di V8 all'altra.
Uno snapshot dell'heap è specifico per un singolo isolato V8. Quando si utilizzano thread worker, uno snapshot dell'heap generato dal thread principale non conterrà alcuna informazione sui worker e viceversa.
La creazione di uno snapshot dell'heap richiede una memoria circa doppia rispetto alle dimensioni dell'heap al momento della creazione dello snapshot. Ciò comporta il rischio che i killer OOM terminino il processo.
La generazione di uno snapshot è un'operazione sincrona che blocca il loop degli eventi per una durata che dipende dalle dimensioni dell'heap.
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}`)
// Ora ottieni un heapdump per il thread principale.
console.log(`main thread heapdump: ${writeHeapSnapshot()}`)
})
// Di' al worker di creare un heapdump.
worker.postMessage('heapdump')
} else {
parentPort.once('message', message => {
if (message === 'heapdump') {
// Genera un heapdump per il worker
// e restituisci il nome del file al padre.
parentPort.postMessage(writeHeapSnapshot())
}
})
}
v8.setHeapSnapshotNearHeapLimit(limit)
Aggiunto in: v18.10.0, v16.18.0
[Stabile: 1 - Sperimentale]
Stabile: 1 Stabilità: 1 - Sperimentale
limit
<intero>
L'API è una no-op se --heapsnapshot-near-heap-limit
è già impostato dalla riga di comando o se l'API viene chiamata più di una volta. limit
deve essere un intero positivo. Vedi --heapsnapshot-near-heap-limit
per maggiori informazioni.
API di serializzazione
L'API di serializzazione fornisce un mezzo per serializzare i valori JavaScript in modo compatibile con l'algoritmo di clonazione strutturata HTML HTML structured clone algorithm.
Il formato è retrocompatibile (cioè sicuro da salvare su disco). Valori JavaScript uguali possono dare origine a output serializzati diversi.
v8.serialize(value)
Aggiunto in: v8.0.0
value
<qualsiasi>- Restituisce: <Buffer>
Utilizza un DefaultSerializer
per serializzare value
in un buffer.
ERR_BUFFER_TOO_LARGE
verrà lanciato quando si tenta di serializzare un oggetto enorme che richiede un buffer più grande di buffer.constants.MAX_LENGTH
.
v8.deserialize(buffer)
Aggiunto in: v8.0.0
buffer
<Buffer> | <TypedArray> | <DataView> Un buffer restituito daserialize()
.
Utilizza un DefaultDeserializer
con opzioni predefinite per leggere un valore JS da un buffer.
Classe: v8.Serializer
Aggiunto in: v8.0.0
new Serializer()
Crea un nuovo oggetto Serializer
.
serializer.writeHeader()
Scrive un'intestazione, che include la versione del formato di serializzazione.
serializer.writeValue(value)
value
<any>
Serializza un valore JavaScript e aggiunge la rappresentazione serializzata al buffer interno.
Questo genera un errore se value
non può essere serializzato.
serializer.releaseBuffer()
- Restituisce: <Buffer>
Restituisce il buffer interno memorizzato. Questo serializer non dovrebbe essere utilizzato una volta rilasciato il buffer. Chiamare questo metodo provoca un comportamento indefinito se una scrittura precedente ha avuto esito negativo.
serializer.transferArrayBuffer(id, arrayBuffer)
id
<integer> Un intero senza segno a 32 bit.arrayBuffer
<ArrayBuffer> Un'istanza diArrayBuffer
.
Segna un ArrayBuffer
come avente il suo contenuto trasferito fuori banda. Passare il corrispondente ArrayBuffer
nel contesto di deserializzazione a deserializer.transferArrayBuffer()
.
serializer.writeUint32(value)
value
<integer>
Scrive un intero senza segno a 32 bit raw. Per l'uso all'interno di un serializer._writeHostObject()
personalizzato.
serializer.writeUint64(hi, lo)
Scrive un intero senza segno a 64 bit raw, suddiviso in parti alte e basse a 32 bit. Per l'uso all'interno di un serializer._writeHostObject()
personalizzato.
serializer.writeDouble(value)
value
<number>
Scrive un valore number
JS. Per l'uso all'interno di un serializer._writeHostObject()
personalizzato.
serializer.writeRawBytes(buffer)
buffer
<Buffer> | <TypedArray> | <DataView>
Scrive byte grezzi nel buffer interno del serializer. Il deserializer richiederà un modo per calcolare la lunghezza del buffer. Per l'uso all'interno di un serializer._writeHostObject()
personalizzato.
serializer._writeHostObject(object)
object
<Object>
Questo metodo viene chiamato per scrivere un qualche tipo di oggetto host, cioè un oggetto creato da binding nativi C++. Se non è possibile serializzare object
, dovrebbe essere sollevata un'eccezione appropriata.
Questo metodo non è presente nella classe Serializer
stessa, ma può essere fornito dalle sottoclassi.
serializer._getDataCloneError(message)
message
<string>
Questo metodo viene chiamato per generare oggetti di errore che verranno sollevati quando un oggetto non può essere clonato.
Questo metodo di default utilizza il costruttore Error
e può essere sovrascritto nelle sottoclassi.
serializer._getSharedArrayBufferId(sharedArrayBuffer)
sharedArrayBuffer
<SharedArrayBuffer>
Questo metodo viene chiamato quando il serializer sta per serializzare un oggetto SharedArrayBuffer
. Deve restituire un ID intero senza segno a 32 bit per l'oggetto, usando lo stesso ID se questo SharedArrayBuffer
è già stato serializzato. Durante la deserializzazione, questo ID verrà passato a deserializer.transferArrayBuffer()
.
Se l'oggetto non può essere serializzato, dovrebbe essere sollevata un'eccezione.
Questo metodo non è presente nella classe Serializer
stessa, ma può essere fornito dalle sottoclassi.
serializer._setTreatArrayBufferViewsAsHostObjects(flag)
flag
<boolean> Default:false
Indica se trattare gli oggetti TypedArray
e DataView
come oggetti host, ovvero passarli a serializer._writeHostObject()
.
Classe: v8.Deserializer
Aggiunto in: v8.0.0
new Deserializer(buffer)
buffer
<Buffer> | <TypedArray> | <DataView> Un buffer restituito daserializer.releaseBuffer()
.
Crea un nuovo oggetto Deserializer
.
deserializer.readHeader()
Legge e convalida un'intestazione (inclusa la versione del formato). Può, ad esempio, rifiutare un formato wire non valido o non supportato. In tal caso, viene sollevata un'eccezione Error
.
deserializer.readValue()
Deserializza un valore JavaScript dal buffer e lo restituisce.
deserializer.transferArrayBuffer(id, arrayBuffer)
id
<integer> Un intero senza segno a 32 bit.arrayBuffer
<ArrayBuffer> | <SharedArrayBuffer> Un'istanza diArrayBuffer
.
Marca un ArrayBuffer
come avente i suoi contenuti trasferiti fuori banda. Passare il corrispondente ArrayBuffer
nel contesto di serializzazione a serializer.transferArrayBuffer()
(o restituire l'id
da serializer._getSharedArrayBufferId()
nel caso di SharedArrayBuffer
).
deserializer.getWireFormatVersion()
- Restituisce: <intero>
Legge la versione sottostante del formato wire. Probabilmente utile soprattutto per codice legacy che legge vecchie versioni del formato wire. Potrebbe non essere chiamato prima di .readHeader()
.
deserializer.readUint32()
- Restituisce: <intero>
Legge un intero senza segno a 32 bit non elaborato e lo restituisce. Per l'uso all'interno di un deserializer._readHostObject()
personalizzato.
deserializer.readUint64()
- Restituisce: <intero[]>
Legge un intero senza segno a 64 bit non elaborato e lo restituisce come un array [hi, lo]
con due voci intere senza segno a 32 bit. Per l'uso all'interno di un deserializer._readHostObject()
personalizzato.
deserializer.readDouble()
- Restituisce: <numero>
Legge un valore number
JS. Per l'uso all'interno di un deserializer._readHostObject()
personalizzato.
deserializer.readRawBytes(length)
Legge i byte non elaborati dal buffer interno del deserializer. Il parametro length
deve corrispondere alla lunghezza del buffer che è stato passato a serializer.writeRawBytes()
. Per l'uso all'interno di un deserializer._readHostObject()
personalizzato.
deserializer._readHostObject()
Questo metodo viene chiamato per leggere un qualche tipo di oggetto host, ovvero un oggetto creato da binding nativi C++. Se non è possibile deserializzare i dati, dovrebbe essere sollevata un'eccezione appropriata.
Questo metodo non è presente sulla classe Deserializer
stessa, ma può essere fornito dalle sottoclassi.
Classe: v8.DefaultSerializer
Aggiunto in: v8.0.0
Una sottoclasse di Serializer
che serializza gli oggetti TypedArray
(in particolare Buffer
) e DataView
come oggetti host, e memorizza solo la parte dei loro ArrayBuffer
sottostanti a cui fanno riferimento.
Classe: v8.DefaultDeserializer
Aggiunto in: v8.0.0
Una sottoclasse di Deserializer
corrispondente al formato scritto da DefaultSerializer
.
Hook delle Promise
L'interfaccia promiseHooks
può essere utilizzata per tracciare gli eventi del ciclo di vita delle promise. Per tracciare tutta l'attività asincrona, vedere async_hooks
che internamente utilizza questo modulo per produrre eventi del ciclo di vita delle promise oltre agli eventi per altre risorse asincrone. Per la gestione del contesto della richiesta, vedere AsyncLocalStorage
.
import { promiseHooks } from 'node:v8'
// Ci sono quattro eventi del ciclo di vita prodotti dalle promise:
// L'evento `init` rappresenta la creazione di una promise. Questo potrebbe essere una
// creazione diretta come con `new Promise(...)` o una continuazione come
// `then()` o `catch()`. Accade anche ogni volta che viene chiamata una funzione asincrona o fa un `await`. Se viene creata una promise di continuazione, il
// `parent` sarà la promise da cui è una continuazione.
function init(promise, parent) {
console.log('una promise è stata creata', { promise, parent })
}
// L'evento `settled` accade quando una promise riceve un valore di risoluzione o
// di rifiuto. Questo può accadere sincronicamente, come quando si usa
// `Promise.resolve()` su input non-promise.
function settled(promise) {
console.log('una promise risolta o rifiutata', { promise })
}
// L'evento `before` viene eseguito immediatamente prima che un gestore `then()` o `catch()`
// venga eseguito o un `await` riprenda l'esecuzione.
function before(promise) {
console.log('una promise sta per chiamare un gestore then', { promise })
}
// L'evento `after` viene eseguito immediatamente dopo che un gestore `then()` viene eseguito o quando
// un `await` inizia dopo aver ripreso da un altro.
function after(promise) {
console.log('una promise ha finito di chiamare un gestore then', { promise })
}
// I hook del ciclo di vita possono essere avviati e arrestati individualmente
const stopWatchingInits = promiseHooks.onInit(init)
const stopWatchingSettleds = promiseHooks.onSettled(settled)
const stopWatchingBefores = promiseHooks.onBefore(before)
const stopWatchingAfters = promiseHooks.onAfter(after)
// Oppure possono essere avviati e arrestati in gruppi
const stopHookSet = promiseHooks.createHook({
init,
settled,
before,
after,
})
// Per arrestare un hook, chiamare la funzione restituita alla sua creazione.
stopWatchingInits()
stopWatchingSettleds()
stopWatchingBefores()
stopWatchingAfters()
stopHookSet()
promiseHooks.onInit(init)
Aggiunto in: v17.1.0, v16.14.0
init
<Function> La callbackinit
da chiamare quando viene creata una promise.- Restituisce: <Function> Chiamata per interrompere l'hook.
L'hook init
deve essere una funzione semplice. Fornire una funzione asincrona genererà un errore in quanto produrrebbe un loop infinito di microtask.
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)
Aggiunto in: v17.1.0, v16.14.0
settled
<Function> La callbacksettled
da chiamare quando una promise viene risolta o rifiutata.- Restituisce: <Function> Chiamata per interrompere l'hook.
L'hook settled
deve essere una funzione semplice. Fornire una funzione asincrona genererà un errore in quanto produrrebbe un loop infinito di microtask.
import { promiseHooks } from 'node:v8'
const stop = promiseHooks.onSettled(promise => {})
const { promiseHooks } = require('node:v8')
const stop = promiseHooks.onSettled(promise => {})
promiseHooks.onBefore(before)
Aggiunto in: v17.1.0, v16.14.0
before
<Function> La callbackbefore
da chiamare prima che venga eseguita una continuazione della promise.- Restituisce: <Function> Chiamata per interrompere l'hook.
L'hook before
deve essere una funzione semplice. Fornire una funzione asincrona genererà un errore in quanto produrrebbe un loop infinito di microtask.
import { promiseHooks } from 'node:v8'
const stop = promiseHooks.onBefore(promise => {})
const { promiseHooks } = require('node:v8')
const stop = promiseHooks.onBefore(promise => {})
promiseHooks.onAfter(after)
Aggiunto in: v17.1.0, v16.14.0
after
<Function> La callbackafter
da chiamare dopo l'esecuzione di una continuazione della promise.- Restituisce: <Function> Chiamata per interrompere l'hook.
L'hook after
deve essere una funzione semplice. Fornire una funzione asincrona genererà un'eccezione in quanto produrrebbe un ciclo infinito di microtask.
import { promiseHooks } from 'node:v8'
const stop = promiseHooks.onAfter(promise => {})
const { promiseHooks } = require('node:v8')
const stop = promiseHooks.onAfter(promise => {})
promiseHooks.createHook(callbacks)
Aggiunto in: v17.1.0, v16.14.0
callbacks
<Object> Le Callback dell'Hook da registrareinit
<Function> La callbackinit
.before
<Function> La callbackbefore
.after
<Function> La callbackafter
.settled
<Function> La callbacksettled
.
Restituisce: <Function> Usato per disabilitare gli hook
Le callback dell'hook devono essere funzioni semplici. Fornire funzioni asincrone genererà un'eccezione in quanto produrrebbe un ciclo infinito di microtask.
Registra le funzioni da chiamare per diversi eventi del ciclo di vita di ogni promise.
Le callback init()
/before()
/after()
/settled()
vengono chiamate per i rispettivi eventi durante il ciclo di vita di una promise.
Tutte le callback sono opzionali. Ad esempio, se è necessario tracciare solo la creazione di una promise, è sufficiente passare solo la callback init
. Le specifiche di tutte le funzioni che possono essere passate a callbacks
si trovano nella sezione Callback dell'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) {},
})
Callback di Hook
Gli eventi chiave nel ciclo di vita di una promise sono stati categorizzati in quattro aree: creazione di una promise, prima/dopo la chiamata di un gestore di continuazione o attorno a un await, e quando la promise si risolve o si rifiuta.
Sebbene questi hook siano simili a quelli di async_hooks
, manca un hook destroy
. Altri tipi di risorse asincrone in genere rappresentano socket o descrittori di file che hanno un distinto stato "chiuso" per esprimere l'evento del ciclo di vita destroy
, mentre le promise rimangono utilizzabili finché il codice può ancora raggiungerle. Il tracciamento della garbage collection viene utilizzato per far entrare le promise nel modello di evento async_hooks
, tuttavia questo tracciamento è molto costoso e potrebbero non essere mai raccolte come garbage.
Poiché le promise sono risorse asincrone il cui ciclo di vita viene tracciato tramite il meccanismo degli hook delle promise, i callback init()
, before()
, after()
, e settled()
non devono essere funzioni asincrone poiché creano più promise che produrrebbero un loop infinito.
Sebbene questa API venga utilizzata per alimentare gli eventi delle promise in async_hooks
, l'ordinamento tra i due è indefinito. Entrambe le API sono multi-tenant e quindi potrebbero produrre eventi in qualsiasi ordine l'una rispetto all'altra.
init(promise, parent)
promise
<Promise> La promise che viene creata.parent
<Promise> La promise da cui si continua, se applicabile.
Chiamato quando viene costruita una promise. Questo non significa che si verificheranno gli eventi before
/after
corrispondenti, solo che esiste la possibilità. Questo accadrà se una promise viene creata senza mai ottenere una continuazione.
before(promise)
promise
<Promise>
Chiamato prima dell'esecuzione di una continuazione della promise. Questo può essere sotto forma di gestori then()
, catch()
o finally()
o di un await
che riprende.
Il callback before
verrà chiamato da 0 a N volte. Il callback before
verrà tipicamente chiamato 0 volte se non è mai stata effettuata alcuna continuazione per la promise. Il callback before
può essere chiamato molte volte nel caso in cui siano state effettuate molte continuazioni dalla stessa promise.
after(promise)
promise
<Promise>
Chiamato immediatamente dopo l'esecuzione di una continuazione di una promise. Questo potrebbe avvenire dopo un gestore then()
, catch()
, o finally()
o prima di un await
dopo un altro await
.
settled(promise)
promise
<Promise>
Chiamato quando la promise riceve un valore di risoluzione o di rifiuto. Questo può avvenire sincronicamente nel caso di Promise.resolve()
o Promise.reject()
.
API Istantanea di Avvio
Aggiunto in: v18.6.0, v16.17.0
[Stabile: 1 - Sperimentale]
Stabile: 1 Stabilità: 1 - Sperimentale
L'interfaccia v8.startupSnapshot
può essere utilizzata per aggiungere hook di serializzazione e deserializzazione per istantanee di avvio personalizzate.
$ node --snapshot-blob snapshot.blob --build-snapshot entry.js
# Questo lancia un processo con l'istantanea {#this-launches-a-process-with-the-snapshot}
$ node --snapshot-blob snapshot.blob
Nell'esempio sopra, entry.js
può utilizzare i metodi dell'interfaccia v8.startupSnapshot
per specificare come salvare le informazioni per gli oggetti personalizzati nell'istantanea durante la serializzazione e come le informazioni possono essere utilizzate per sincronizzare questi oggetti durante la deserializzazione dell'istantanea. Ad esempio, se entry.js
contiene lo script seguente:
'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()
// Lettura di una serie di file dalla directory e memorizzazione nella 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 qui è dove lo script dell'istantanea è posizionato
// durante il tempo di creazione dell'istantanea.
const shelf = new BookShelf(__dirname, ['book1.en_US.txt', 'book1.es_ES.txt', 'book2.zh_CN.txt'])
assert(v8.startupSnapshot.isBuildingSnapshot())
// Sulla serializzazione dell'istantanea, comprimere i libri per ridurre le dimensioni.
v8.startupSnapshot.addSerializeCallback(BookShelf.compressAll, shelf)
// Sulla deserializzazione dell'istantanea, decomprimere i libri.
v8.startupSnapshot.addDeserializeCallback(BookShelf.decompressAll, shelf)
v8.startupSnapshot.setDeserializeMainFunction(shelf => {
// process.env e process.argv vengono aggiornati durante la deserializzazione dell'istantanea.
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)
Il binario risultante stamperà i dati deserializzati dall'istantanea durante l'avvio, utilizzando process.env
e process.argv
aggiornati del processo lanciato:
$ BOOK_LANG=es_ES node --snapshot-blob snapshot.blob book1
# Stampa il contenuto di book1.es_ES.txt deserializzato dall'istantanea. {#prints-content-of-book1es_estxt-deserialized-from-the-snapshot}
Attualmente l'applicazione deserializzata da un'istantanea utente non può essere nuovamente istantaneizzata, quindi queste API sono disponibili solo per le applicazioni che non sono deserializzate da un'istantanea utente.
v8.startupSnapshot.addSerializeCallback(callback[, data])
Aggiunto in: v18.6.0, v16.17.0
callback
<Function> Callback da invocare prima della serializzazione.data
<any> Dati opzionali che verranno passati alcallback
quando viene chiamato.
Aggiunge un callback che verrà chiamato quando l'istanza di Node.js sta per essere serializzata in uno snapshot e uscire. Questo può essere utilizzato per rilasciare risorse che non dovrebbero o non possono essere serializzate o per convertire i dati utente in una forma più adatta alla serializzazione.
I callback vengono eseguiti nell'ordine in cui vengono aggiunti.
v8.startupSnapshot.addDeserializeCallback(callback[, data])
Aggiunto in: v18.6.0, v16.17.0
callback
<Function> Callback da invocare dopo che lo snapshot è stato deserializzato.data
<any> Dati opzionali che verranno passati alcallback
quando viene chiamato.
Aggiunge un callback che verrà chiamato quando l'istanza di Node.js viene deserializzata da uno snapshot. Il callback
e i data
(se forniti) verranno serializzati nello snapshot; possono essere utilizzati per re-inizializzare lo stato dell'applicazione o per riacquisire le risorse di cui l'applicazione ha bisogno quando l'applicazione viene riavviata dallo snapshot.
I callback vengono eseguiti nell'ordine in cui vengono aggiunti.
v8.startupSnapshot.setDeserializeMainFunction(callback[, data])
Aggiunto in: v18.6.0, v16.17.0
callback
<Function> Callback da invocare come punto di ingresso dopo che lo snapshot è stato deserializzato.data
<any> Dati opzionali che verranno passati alcallback
quando viene chiamato.
Questo imposta il punto di ingresso dell'applicazione Node.js quando viene deserializzata da uno snapshot. Questo può essere chiamato solo una volta nello script di creazione dello snapshot. Se chiamato, l'applicazione deserializzata non necessita più di uno script di punto di ingresso aggiuntivo per l'avvio e invocherà semplicemente il callback insieme ai dati deserializzati (se forniti), altrimenti è comunque necessario fornire uno script di punto di ingresso all'applicazione deserializzata.
v8.startupSnapshot.isBuildingSnapshot()
Aggiunto in: v18.6.0, v16.17.0
- Restituisce: <boolean>
Restituisce true
se l'istanza di Node.js viene eseguita per creare uno snapshot.
Classe: v8.GCProfiler
Aggiunto in: v19.6.0, v18.15.0
Questa API raccoglie i dati GC nel thread corrente.
new v8.GCProfiler()
Aggiunto in: v19.6.0, v18.15.0
Crea una nuova istanza della classe v8.GCProfiler
.
profiler.start()
Aggiunto in: v19.6.0, v18.15.0
Inizia a raccogliere i dati GC.
profiler.stop()
Aggiunto in: v19.6.0, v18.15.0
Arresta la raccolta dei dati GC e restituisce un oggetto. Il contenuto dell'oggetto è il seguente.
{
"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
}
Ecco un esempio.
const { GCProfiler } = require('node:v8')
const profiler = new GCProfiler()
profiler.start()
setTimeout(() => {
console.log(profiler.stop())
}, 1000)