V8
Code source : lib/v8.js
Le module node:v8
expose des API spécifiques à la version de V8 intégrée au binaire Node.js. Il est accessible en utilisant :
const v8 = require('node:v8');
v8.cachedDataVersionTag()
Ajouté dans : v8.0.0
- Retourne : <integer>
Retourne un entier représentant une balise de version dérivée de la version de V8, des indicateurs de ligne de commande et des fonctionnalités de CPU détectées. Ceci est utile pour déterminer si un tampon cachedData
de vm.Script
est compatible avec cette instance de V8.
console.log(v8.cachedDataVersionTag()); // 3947234607
// La valeur retournée par v8.cachedDataVersionTag() est dérivée de la version de V8,
// des indicateurs de ligne de commande et des fonctionnalités de CPU détectées. Vérifiez
// que la valeur est bien mise à jour lorsque les indicateurs sont activés/désactivés.
v8.setFlagsFromString('--allow_natives_syntax');
console.log(v8.cachedDataVersionTag()); // 183726201
v8.getHeapCodeStatistics()
Ajouté dans : v12.8.0
- Retourne : <Object>
Obtenez des statistiques sur le code et ses métadonnées dans le tas, voir l'API V8 GetHeapCodeAndMetadataStatistics
. Retourne un objet avec les propriétés suivantes :
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])
[Historique]
Version | Modifications |
---|---|
v19.1.0 | Prise en charge des options pour configurer le snapshot du tas. |
v11.13.0 | Ajouté dans : v11.13.0 |
options
<Object>Retourne : <stream.Readable> Un Readable contenant le snapshot du tas V8.
Génère un snapshot du tas V8 actuel et renvoie un flux Readable qui peut être utilisé pour lire la représentation sérialisée JSON. Ce format de flux JSON est destiné à être utilisé avec des outils tels que Chrome DevTools. Le schéma JSON n’est pas documenté et est spécifique au moteur V8. Par conséquent, le schéma peut changer d’une version de V8 à l’autre.
La création d’un snapshot du tas nécessite une mémoire environ deux fois supérieure à la taille du tas au moment où le snapshot est créé. Cela entraîne le risque que les tueurs OOM mettent fin au processus.
La génération d’un snapshot est une opération synchrone qui bloque la boucle d’événements pendant une durée dépendant de la taille du tas.
// Imprimer le snapshot du tas dans la console
const v8 = require('node:v8');
const stream = v8.getHeapSnapshot();
stream.pipe(process.stdout);
v8.getHeapSpaceStatistics()
[Historique]
Version | Modifications |
---|---|
v7.5.0 | Prise en charge des valeurs dépassant la plage d’entiers non signés de 32 bits. |
v6.0.0 | Ajouté dans : v6.0.0 |
- Retourne : <Object[]>
Retourne des statistiques sur les espaces de tas V8, c’est-à-dire les segments qui composent le tas V8. Ni l’ordre des espaces de tas, ni la disponibilité d’un espace de tas ne peuvent être garantis, car les statistiques sont fournies via la fonction V8 GetHeapSpaceStatistics
et peuvent changer d’une version de V8 à l’autre.
La valeur renvoyée est un tableau d’objets contenant les propriétés suivantes :
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()
[Historique]
Version | Modifications |
---|---|
v7.5.0 | Prise en charge des valeurs dépassant la plage d'entiers non signés 32 bits. |
v7.2.0 | Ajout de malloced_memory , peak_malloced_memory et does_zap_garbage . |
v1.0.0 | Ajoutée dans : v1.0.0 |
- Retourne : <Object>
Retourne un objet avec les propriétés suivantes :
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
La valeur de total_heap_size est le nombre d'octets que V8 a alloués pour le tas. Cette valeur peut augmenter si used_heap a besoin de plus de mémoire.
total_heap_size_executable
La valeur de total_heap_size_executable est la portion du tas qui peut contenir du code exécutable, en octets. Cela inclut la mémoire utilisée par le code compilé JIT et toute mémoire qui doit être conservée comme exécutable.
total_physical_size
La valeur de total_physical_size est la mémoire physique réelle utilisée par le tas V8, en octets. Il s'agit de la quantité de mémoire qui est engagée (ou en cours d'utilisation) plutôt que réservée.
total_available_size
La valeur de total_available_size est le nombre d'octets de mémoire disponibles pour le tas V8. Cette valeur représente la quantité de mémoire supplémentaire que V8 peut utiliser avant de dépasser la limite du tas.
used_heap_size
La valeur de used_heap_size est le nombre d'octets actuellement utilisés par les objets JavaScript de V8. Il s'agit de la mémoire réelle en cours d'utilisation et n'inclut pas la mémoire qui a été allouée mais pas encore utilisée.
heap_size_limit
La valeur de heap_size_limit est la taille maximale du tas V8, en octets (soit la limite par défaut, déterminée par les ressources du système, soit la valeur transmise à l'option --max_old_space_size
).
malloced_memory
La valeur de malloced_memory est le nombre d'octets alloués via malloc
par V8.
peak_malloced_memory
La valeur de peak_malloced_memory est le nombre maximal d'octets alloués via malloc
par V8 pendant la durée de vie du processus.
does_zap_garbage
est un booléen 0/1, qui indique si l'option --zap_code_space
est activée ou non. Cela permet à V8 de remplacer les déchets du tas par un motif binaire. L'empreinte RSS (resident set size) augmente car elle touche continuellement toutes les pages du tas, ce qui les rend moins susceptibles d'être échangées par le système d'exploitation.
number_of_native_contexts
La valeur de native_context est le nombre de contextes de niveau supérieur actuellement actifs. L'augmentation de ce nombre au fil du temps indique une fuite de mémoire.
number_of_detached_contexts
La valeur de detached_context est le nombre de contextes qui ont été détachés et pas encore collectés par le garbage collector. Si ce nombre est non nul, cela indique une fuite de mémoire potentielle.
total_global_handles_size
La valeur de total_global_handles_size est la taille totale de la mémoire des handles globaux V8.
used_global_handles_size
La valeur de used_global_handles_size est la taille de la mémoire utilisée des handles globaux V8.
external_memory
La valeur de external_memory est la taille de la mémoire des tampons de tableau et des chaînes externes.
{
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])
Ajouté dans : v22.0.0, v20.13.0
[Stable: 1 - Expérimental]
Stable: 1 Stability: 1.1 - Développement actif
ctor
<Function> Le constructeur qui peut être utilisé pour rechercher dans la chaîne de prototypes afin de filtrer les objets cibles dans le tas.options
<undefined> | <Object>format
<string> Si c'est'count'
, le nombre d'objets correspondants est renvoyé. Si c'est'summary'
, un tableau avec des chaînes de résumé des objets correspondants est renvoyé.
Retourne : {number|Array
Ceci est similaire à l'API queryObjects()
console API fournie par la console Chromium DevTools. Elle peut être utilisée pour rechercher des objets qui ont le constructeur correspondant dans leur chaîne de prototypes dans le tas après une collecte complète des déchets, ce qui peut être utile pour les tests de régression de fuite de mémoire. Pour éviter des résultats surprenants, les utilisateurs doivent éviter d'utiliser cette API sur des constructeurs dont ils ne contrôlent pas l'implémentation, ou sur des constructeurs qui peuvent être invoqués par d'autres parties de l'application.
Pour éviter les fuites accidentelles, cette API ne renvoie pas de références brutes aux objets trouvés. Par défaut, elle renvoie le nombre d'objets trouvés. Si options.format
est 'summary'
, elle renvoie un tableau contenant de brèves représentations sous forme de chaîne pour chaque objet. La visibilité fournie dans cette API est similaire à celle fournie par l'instantané de tas, tandis que les utilisateurs peuvent économiser le coût de la sérialisation et de l'analyse et filtrer directement les objets cibles pendant la recherche.
Seuls les objets créés dans le contexte d'exécution actuel sont inclus dans les résultats.
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' }));
// Notez que, lorsqu'il y a des classes enfants héritant d'un constructeur,
// le constructeur apparaît également dans la chaîne de prototypes du
// prototype des classes enfants, donc le prototype des classes enfants
// serait également inclus dans le résultat.
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' }));
// Notez que, lorsqu'il y a des classes enfants héritant d'un constructeur,
// le constructeur apparaît également dans la chaîne de prototypes du
// prototype des classes enfants, donc le prototype des classes enfants
// serait également inclus dans le résultat.
console.log(queryObjects(A)); // 3
// [ "B { foo: 'bar', bar: 'qux' }", 'A {}', "A { foo: 'bar' }" ]
console.log(queryObjects(A, { format: 'summary' }));
v8.setFlagsFromString(flags)
Ajoutée dans : v1.0.0
flags
<string>
La méthode v8.setFlagsFromString()
peut être utilisée pour définir par programme les indicateurs de ligne de commande V8. Cette méthode doit être utilisée avec précaution. La modification des paramètres après le démarrage de la VM peut entraîner un comportement imprévisible, notamment des plantages et des pertes de données, ou elle peut simplement ne rien faire.
Les options V8 disponibles pour une version de Node.js peuvent être déterminées en exécutant node --v8-options
.
Utilisation :
// Imprimer les événements GC sur stdout pendant une minute.
const v8 = require('node:v8');
v8.setFlagsFromString('--trace_gc');
setTimeout(() => { v8.setFlagsFromString('--notrace_gc'); }, 60e3);
v8.stopCoverage()
Ajoutée dans : v15.1.0, v14.18.0, v12.22.0
La méthode v8.stopCoverage()
permet à l'utilisateur d'arrêter la collecte de la couverture lancée par NODE_V8_COVERAGE
, afin que V8 puisse libérer les enregistrements de nombre d'exécutions et optimiser le code. Ceci peut être utilisé conjointement avec v8.takeCoverage()
si l'utilisateur souhaite collecter la couverture à la demande.
v8.takeCoverage()
Ajoutée dans : v15.1.0, v14.18.0, v12.22.0
La méthode v8.takeCoverage()
permet à l'utilisateur d'écrire la couverture lancée par NODE_V8_COVERAGE
sur le disque à la demande. Cette méthode peut être invoquée plusieurs fois pendant la durée de vie du processus. Chaque fois, le compteur d'exécution sera réinitialisé et un nouveau rapport de couverture sera écrit dans le répertoire spécifié par NODE_V8_COVERAGE
.
Lorsque le processus est sur le point de se terminer, une dernière couverture sera toujours écrite sur le disque, à moins que v8.stopCoverage()
ne soit invoqué avant la fin du processus.
v8.writeHeapSnapshot([filename[,options]])
[Historique]
Version | Modifications |
---|---|
v19.1.0 | Prise en charge des options pour configurer l'instantané de tas. |
v18.0.0 | Une exception sera maintenant levée si le fichier n'a pas pu être écrit. |
v18.0.0 | Rendre les codes d'erreur renvoyés cohérents sur toutes les plateformes. |
v11.13.0 | Ajoutée dans : v11.13.0 |
filename
<string> Le chemin d'accès au fichier où l'instantané du tas V8 doit être enregistré. Si non spécifié, un nom de fichier avec le motif'Heap-${yyyymmdd}-${hhmmss}-${pid}-${thread_id}.heapsnapshot'
sera généré, où{pid}
sera le PID du processus Node.js,{thread_id}
sera0
lorsquewriteHeapSnapshot()
est appelé depuis le thread principal Node.js ou l'id d'un thread worker.options
<Object>Retourne : <string> Le nom du fichier où l'instantané a été enregistré.
Génère un instantané du tas V8 actuel et l'écrit dans un fichier JSON. Ce fichier est destiné à être utilisé avec des outils tels que Chrome DevTools. Le schéma JSON n'est pas documenté et est spécifique au moteur V8, et peut changer d'une version de V8 à l'autre.
Un instantané du tas est spécifique à un seul isolat V8. Lors de l'utilisation de threads de worker, un instantané du tas généré à partir du thread principal ne contiendra aucune information sur les workers, et vice versa.
La création d'un instantané du tas nécessite une mémoire d'environ deux fois la taille du tas au moment où l'instantané est créé. Cela entraîne le risque que les terminateurs OOM mettent fin au processus.
La génération d'un instantané est une opération synchrone qui bloque la boucle d'événements pendant une durée dépendant de la taille du tas.
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}`);
// Maintenant, obtenez un heapdump pour le thread principal.
console.log(`main thread heapdump: ${writeHeapSnapshot()}`);
});
// Indiquez au worker de créer un heapdump.
worker.postMessage('heapdump');
} else {
parentPort.once('message', (message) => {
if (message === 'heapdump') {
// Générez un heapdump pour le worker
// et renvoyez le nom de fichier au parent.
parentPort.postMessage(writeHeapSnapshot());
}
});
}
v8.setHeapSnapshotNearHeapLimit(limit)
Ajouté dans : v18.10.0, v16.18.0
[Stable: 1 - Experimental]
Stable : 1 Stabilité : 1 - Expérimental
limit
<integer>
L’API est sans effet si --heapsnapshot-near-heap-limit
est déjà défini à partir de la ligne de commande ou si l’API est appelée plus d’une fois. limit
doit être un entier positif. Voir --heapsnapshot-near-heap-limit
pour plus d’informations.
API de sérialisation
L’API de sérialisation fournit des moyens de sérialiser des valeurs JavaScript d’une manière compatible avec l’algorithme de clonage structuré HTML.
Le format est rétrocompatible (c’est-à-dire qu’il peut être stocké sur disque en toute sécurité). Des valeurs JavaScript égales peuvent donner lieu à des sorties sérialisées différentes.
v8.serialize(value)
Ajouté dans : v8.0.0
Utilise un DefaultSerializer
pour sérialiser value
dans un tampon.
ERR_BUFFER_TOO_LARGE
sera lancé lors de la tentative de sérialisation d’un objet énorme qui nécessite un tampon plus grand que buffer.constants.MAX_LENGTH
.
v8.deserialize(buffer)
Ajouté dans : v8.0.0
buffer
<Buffer> | <TypedArray> | <DataView> Un tampon renvoyé parserialize()
.
Utilise un DefaultDeserializer
avec les options par défaut pour lire une valeur JS à partir d’un tampon.
Classe : v8.Serializer
Ajouté dans : v8.0.0
new Serializer()
Crée un nouvel objet Serializer
.
serializer.writeHeader()
Écrit un en-tête, qui inclut la version du format de sérialisation.
serializer.writeValue(value)
value
<any>
Sérialise une valeur JavaScript et ajoute la représentation sérialisée au tampon interne.
Ceci lève une erreur si value
ne peut pas être sérialisée.
serializer.releaseBuffer()
- Retourne : <Buffer>
Retourne le tampon interne stocké. Ce sérialiseur ne doit pas être utilisé une fois le tampon libéré. L’appel de cette méthode entraîne un comportement indéfini si une écriture précédente a échoué.
serializer.transferArrayBuffer(id, arrayBuffer)
id
<integer> Un entier non signé de 32 bits.arrayBuffer
<ArrayBuffer> Une instance deArrayBuffer
.
Marque un ArrayBuffer
comme ayant son contenu transféré hors bande. Passez le ArrayBuffer
correspondant dans le contexte de désérialisation à deserializer.transferArrayBuffer()
.
serializer.writeUint32(value)
value
<integer>
Écrit un entier brut non signé de 32 bits. À utiliser à l’intérieur d’un serializer._writeHostObject()
personnalisé.
serializer.writeUint64(hi, lo)
Écrit un entier brut non signé de 64 bits, divisé en parties haute et basse de 32 bits. À utiliser à l’intérieur d’un serializer._writeHostObject()
personnalisé.
serializer.writeDouble(value)
value
<number>
Écrit une valeur JS number
. À utiliser à l'intérieur d'un serializer._writeHostObject()
personnalisé.
serializer.writeRawBytes(buffer)
buffer
<Buffer> | <TypedArray> | <DataView>
Écrit des octets bruts dans le buffer interne du sérialiseur. Le désérialiseur aura besoin d'un moyen de calculer la longueur du buffer. À utiliser à l'intérieur d'un serializer._writeHostObject()
personnalisé.
serializer._writeHostObject(object)
object
<Object>
Cette méthode est appelée pour écrire une sorte d'objet hôte, c'est-à-dire un objet créé par des liaisons C++ natives. S'il n'est pas possible de sérialiser object
, une exception appropriée doit être levée.
Cette méthode n'est pas présente sur la classe Serializer
elle-même, mais peut être fournie par les sous-classes.
serializer._getDataCloneError(message)
message
<string>
Cette méthode est appelée pour générer des objets d'erreur qui seront levés lorsqu'un objet ne peut pas être cloné.
Cette méthode est par défaut le constructeur Error
et peut être remplacée sur les sous-classes.
serializer._getSharedArrayBufferId(sharedArrayBuffer)
sharedArrayBuffer
<SharedArrayBuffer>
Cette méthode est appelée lorsque le sérialiseur va sérialiser un objet SharedArrayBuffer
. Il doit renvoyer un ID entier non signé de 32 bits pour l'objet, en utilisant le même ID si ce SharedArrayBuffer
a déjà été sérialisé. Lors de la désérialisation, cet ID sera transmis à deserializer.transferArrayBuffer()
.
Si l'objet ne peut pas être sérialisé, une exception doit être levée.
Cette méthode n'est pas présente sur la classe Serializer
elle-même, mais peut être fournie par les sous-classes.
serializer._setTreatArrayBufferViewsAsHostObjects(flag)
flag
<boolean> Par défaut :false
Indique s’il faut traiter les objets TypedArray
et DataView
comme des objets hôtes, c’est-à-dire les passer à serializer._writeHostObject()
.
Classe : v8.Deserializer
Ajoutée dans : v8.0.0
new Deserializer(buffer)
buffer
<Buffer> | <TypedArray> | <DataView> Un tampon renvoyé parserializer.releaseBuffer()
.
Crée un nouvel objet Deserializer
.
deserializer.readHeader()
Lit et valide un en-tête (y compris la version du format). Peut, par exemple, rejeter un format filaire non valide ou non pris en charge. Dans ce cas, une Error
est levée.
deserializer.readValue()
Désérialise une valeur JavaScript à partir du tampon et la renvoie.
deserializer.transferArrayBuffer(id, arrayBuffer)
id
<integer> Un entier non signé de 32 bits.arrayBuffer
<ArrayBuffer> | <SharedArrayBuffer> Une instanceArrayBuffer
.
Marque un ArrayBuffer
comme ayant son contenu transféré hors bande. Passez le ArrayBuffer
correspondant dans le contexte de sérialisation à serializer.transferArrayBuffer()
(ou renvoyez l'id
depuis serializer._getSharedArrayBufferId()
dans le cas des SharedArrayBuffer
).
deserializer.getWireFormatVersion()
- Returns: <integer>
Lit la version du format filaire sous-jacent. Utile probablement surtout au code hérité lisant d'anciennes versions du format filaire. Ne peut pas être appelé avant .readHeader()
.
deserializer.readUint32()
- Returns: <integer>
Lit un entier non signé brut de 32 bits et le renvoie. À utiliser à l'intérieur d'un deserializer._readHostObject()
personnalisé.
deserializer.readUint64()
- Returns: <integer[]>
Lit un entier non signé brut de 64 bits et le renvoie sous la forme d'un tableau [hi, lo]
avec deux entrées d'entiers non signés de 32 bits. À utiliser à l'intérieur d'un deserializer._readHostObject()
personnalisé.
deserializer.readDouble()
- Returns: <number>
Lit une valeur number
JS. À utiliser à l'intérieur d'un deserializer._readHostObject()
personnalisé.
deserializer.readRawBytes(length)
Lit les octets bruts du tampon interne du désérialiseur. Le paramètre length
doit correspondre à la longueur du tampon qui a été passé à serializer.writeRawBytes()
. À utiliser à l'intérieur d'un deserializer._readHostObject()
personnalisé.
deserializer._readHostObject()
Cette méthode est appelée pour lire une sorte d'objet hôte, c'est-à-dire un objet créé par des liaisons C++ natives. S'il n'est pas possible de désérialiser les données, une exception appropriée doit être levée.
Cette méthode n'est pas présente sur la classe Deserializer
elle-même, mais peut être fournie par des sous-classes.
Classe : v8.DefaultSerializer
Ajoutée dans : v8.0.0
Une sous-classe de Serializer
qui sérialise les objets TypedArray
(en particulier Buffer
) et DataView
en tant qu’objets hôtes, et stocke uniquement la partie de leurs ArrayBuffer
sous-jacents auxquelles ils font référence.
Classe : v8.DefaultDeserializer
Ajoutée dans : v8.0.0
Une sous-classe de Deserializer
correspondant au format écrit par DefaultSerializer
.
Hooks de Promise
L'interface promiseHooks
peut être utilisée pour suivre les événements de cycle de vie des promesses. Pour suivre toute l'activité asynchrone, consultez async_hooks
qui utilise en interne ce module pour produire des événements de cycle de vie des promesses en plus des événements pour d'autres ressources asynchrones. Pour la gestion du contexte des requêtes, consultez AsyncLocalStorage
.
import { promiseHooks } from 'node:v8';
// Les promesses produisent quatre événements de cycle de vie :
// L'événement `init` représente la création d'une promesse. Il peut s'agir d'une
// création directe comme avec `new Promise(...)` ou d'une continuation telle
// que `then()` ou `catch()`. Cela se produit également chaque fois qu'une fonction asynchrone est
// appelée ou effectue un `await`. Si une promesse de continuation est créée, le
// `parent` sera la promesse dont elle est une continuation.
function init(promise, parent) {
console.log('une promesse a été créée', { promise, parent });
}
// L'événement `settled` se produit lorsqu'une promesse reçoit une résolution ou
// une valeur de rejet. Cela peut se produire de manière synchrone, par exemple lors de l'utilisation de
// `Promise.resolve()` sur une entrée non-promesse.
function settled(promise) {
console.log('une promesse résolue ou rejetée', { promise });
}
// L'événement `before` s'exécute immédiatement avant l'exécution d'un gestionnaire `then()` ou `catch()`
// ou avant qu'un `await` ne reprenne l'exécution.
function before(promise) {
console.log('une promesse est sur le point d'appeler un gestionnaire then', { promise });
}
// L'événement `after` s'exécute immédiatement après l'exécution d'un gestionnaire `then()` ou lorsque
// un `await` commence après une reprise depuis un autre.
function after(promise) {
console.log('une promesse a terminé d'appeler un gestionnaire then', { promise });
}
// Les hooks de cycle de vie peuvent être démarrés et arrêtés individuellement
const stopWatchingInits = promiseHooks.onInit(init);
const stopWatchingSettleds = promiseHooks.onSettled(settled);
const stopWatchingBefores = promiseHooks.onBefore(before);
const stopWatchingAfters = promiseHooks.onAfter(after);
// Ou ils peuvent être démarrés et arrêtés en groupes
const stopHookSet = promiseHooks.createHook({
init,
settled,
before,
after,
});
// Pour arrêter un hook, appelez la fonction renvoyée lors de sa création.
stopWatchingInits();
stopWatchingSettleds();
stopWatchingBefores();
stopWatchingAfters();
stopHookSet();
promiseHooks.onInit(init)
Ajouté dans : v17.1.0, v16.14.0
init
<Function> Lecallback init
à appeler lorsqu'une promesse est créée.- Retourne : <Function> Appel pour arrêter le hook.
Le hook init
doit être une fonction simple. Fournir une fonction asynchrone lèvera une erreur car cela produirait une boucle de microtâche infinie.
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)
Ajouté dans : v17.1.0, v16.14.0
settled
<Function> Lecallback settled
à appeler lorsqu'une promesse est résolue ou rejetée.- Retourne : <Function> Appel pour arrêter le hook.
Le hook settled
doit être une fonction simple. Fournir une fonction asynchrone lèvera une erreur car cela produirait une boucle de microtâche infinie.
import { promiseHooks } from 'node:v8';
const stop = promiseHooks.onSettled((promise) => {});
const { promiseHooks } = require('node:v8');
const stop = promiseHooks.onSettled((promise) => {});
promiseHooks.onBefore(before)
Ajouté dans : v17.1.0, v16.14.0
before
<Function> Lecallback before
à appeler avant l'exécution de la continuation d'une promesse.- Retourne : <Function> Appel pour arrêter le hook.
Le hook before
doit être une fonction simple. Fournir une fonction asynchrone lèvera une erreur car cela produirait une boucle de microtâche infinie.
import { promiseHooks } from 'node:v8';
const stop = promiseHooks.onBefore((promise) => {});
const { promiseHooks } = require('node:v8');
const stop = promiseHooks.onBefore((promise) => {});
promiseHooks.onAfter(after)
Ajouté dans : v17.1.0, v16.14.0
after
<Fonction> Lafonction de rappel after
à appeler après l’exécution d’une continuation de promise.- Retourne : <Fonction> Appeler pour arrêter le hook.
Le hook after
doit être une fonction simple. Fournir une fonction async générera une erreur car cela produirait une boucle de microtâche infinie.
import { promiseHooks } from 'node:v8';
const stop = promiseHooks.onAfter((promise) => {});
const { promiseHooks } = require('node:v8');
const stop = promiseHooks.onAfter((promise) => {});
promiseHooks.createHook(callbacks)
Ajouté dans : v17.1.0, v16.14.0
callbacks
<Objet> Les Fonctions de rappel de Hook à enregistrerinit
<Fonction> Lafonction de rappel init
.before
<Fonction> Lafonction de rappel before
.after
<Fonction> Lafonction de rappel after
.settled
<Fonction> Lafonction de rappel settled
.
Retourne : <Fonction> Utilisé pour désactiver les hooks
Les fonctions de rappel du hook doivent être des fonctions simples. Fournir des fonctions async générera une erreur car cela produirait une boucle de microtâche infinie.
Enregistre les fonctions à appeler pour différents événements de durée de vie de chaque promise.
Les fonctions de rappel init()
/before()
/after()
/settled()
sont appelées pour les événements respectifs pendant la durée de vie d’une promise.
Toutes les fonctions de rappel sont facultatives. Par exemple, si seule la création de promise doit être suivie, seule la fonction de rappel init
doit être passée. Les spécificités de toutes les fonctions qui peuvent être passées à callbacks
se trouvent dans la section Fonctions de rappel 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) {},
});
Callbacks de Hook
Les événements clés du cycle de vie d'une promesse ont été classés en quatre domaines : création d'une promesse, avant/après l'appel d'un gestionnaire de continuation ou autour d'un await
, et lorsque la promesse est résolue ou rejetée.
Bien que ces hooks soient similaires à ceux de async_hooks
, ils n'ont pas de hook destroy
. D'autres types de ressources asynchrones représentent généralement des sockets ou des descripteurs de fichiers qui ont un état "fermé" distinct pour exprimer l'événement de cycle de vie destroy
, tandis que les promesses restent utilisables tant que le code peut encore les atteindre. Le suivi du garbage collection est utilisé pour faire correspondre les promesses au modèle d'événements async_hooks
, cependant ce suivi est très coûteux et elles peuvent même ne jamais être garbage collectées.
Étant donné que les promesses sont des ressources asynchrones dont le cycle de vie est suivi via le mécanisme des hooks de promesse, les callbacks init()
, before()
, after()
et settled()
ne doivent pas être des fonctions asynchrones car elles créent davantage de promesses, ce qui produirait une boucle infinie.
Bien que cette API soit utilisée pour alimenter les événements de promesse dans async_hooks
, l'ordre entre les deux n'est pas défini. Les deux API sont multi-locataires et peuvent donc produire des événements dans n'importe quel ordre l'une par rapport à l'autre.
init(promise, parent)
promise
<Promise> La promesse en cours de création.parent
<Promise> La promesse continuée à partir de, le cas échéant.
Appelé lorsqu'une promesse est construite. Cela ne signifie pas que les événements before
/after
correspondants se produiront, mais seulement que la possibilité existe. Cela se produira si une promesse est créée sans jamais obtenir de continuation.
before(promise)
promise
<Promise>
Appelé avant l'exécution d'une continuation de promesse. Cela peut se présenter sous la forme de gestionnaires then()
, catch()
ou finally()
ou d'un await
reprenant.
Le callback before
sera appelé de 0 à N fois. Le callback before
sera généralement appelé 0 fois si aucune continuation n'a jamais été faite pour la promesse. Le callback before
peut être appelé plusieurs fois dans le cas où de nombreuses continuations ont été faites à partir de la même promesse.
after(promise)
promise
<Promise>
Appelé immédiatement après l'exécution d'une continuation de promise. Cela peut se produire après un gestionnaire then()
, catch()
ou finally()
ou avant un await
après un autre await
.
settled(promise)
promise
<Promise>
Appelé lorsque la promise reçoit une valeur de résolution ou de rejet. Cela peut se produire de manière synchrone dans le cas de Promise.resolve()
ou Promise.reject()
.
API Startup Snapshot
Ajouté dans : v18.6.0, v16.17.0
[Stable : 1 - Expérimental]
Stable: 1 Stability: 1 - Expérimental
L'interface v8.startupSnapshot
peut être utilisée pour ajouter des hooks de sérialisation et de désérialisation pour les snapshots de démarrage personnalisés.
$ node --snapshot-blob snapshot.blob --build-snapshot entry.js
# Cela lance un processus avec le snapshot {#this-launches-a-process-with-the-snapshot}
$ node --snapshot-blob snapshot.blob
Dans l'exemple ci-dessus, entry.js
peut utiliser des méthodes de l'interface v8.startupSnapshot
pour spécifier comment enregistrer des informations pour les objets personnalisés dans le snapshot pendant la sérialisation et comment les informations peuvent être utilisées pour synchroniser ces objets pendant la désérialisation du snapshot. Par exemple, si entry.js
contient le script suivant :
'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 ici est l'endroit où le script de snapshot est placé
// pendant la phase de construction du snapshot.
const shelf = new BookShelf(__dirname, [
'book1.en_US.txt',
'book1.es_ES.txt',
'book2.zh_CN.txt',
]);
assert(v8.startupSnapshot.isBuildingSnapshot());
// Lors de la sérialisation du snapshot, compressez les livres pour réduire la taille.
v8.startupSnapshot.addSerializeCallback(BookShelf.compressAll, shelf);
// Lors de la désérialisation du snapshot, décompressez les livres.
v8.startupSnapshot.addDeserializeCallback(BookShelf.decompressAll, shelf);
v8.startupSnapshot.setDeserializeMainFunction((shelf) => {
// process.env et process.argv sont actualisés pendant la désérialisation du snapshot.
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);
Le binaire résultant affichera les données désérialisées à partir du snapshot au démarrage, en utilisant les process.env
et process.argv
actualisés du processus lancé :
$ BOOK_LANG=es_ES node --snapshot-blob snapshot.blob book1
# Affiche le contenu de book1.es_ES.txt désérialisé à partir du snapshot. {#prints-content-of-book1es_estxt-deserialized-from-the-snapshot}
Actuellement, l'application désérialisée à partir d'un snapshot de l'espace utilisateur ne peut pas être à nouveau snapshotée, ces API ne sont donc disponibles que pour les applications qui ne sont pas désérialisées à partir d'un snapshot de l'espace utilisateur.
v8.startupSnapshot.addSerializeCallback(callback[, data])
Ajoutée dans : v18.6.0, v16.17.0
callback
<Function> Callback à invoquer avant la sérialisation.data
<any> Données optionnelles qui seront transmises aucallback
lorsqu'il sera appelé.
Ajoute un callback qui sera appelé lorsque l'instance Node.js est sur le point d'être sérialisée dans un instantané et de se fermer. Ceci peut être utilisé pour libérer des ressources qui ne devraient pas ou ne peuvent pas être sérialisées, ou pour convertir des données utilisateur dans une forme plus adaptée à la sérialisation.
Les callbacks sont exécutés dans l'ordre dans lequel ils sont ajoutés.
v8.startupSnapshot.addDeserializeCallback(callback[, data])
Ajoutée dans : v18.6.0, v16.17.0
callback
<Function> Callback à invoquer après la désérialisation de l'instantané.data
<any> Données optionnelles qui seront transmises aucallback
lorsqu'il sera appelé.
Ajoute un callback qui sera appelé lorsque l'instance Node.js est désérialisée à partir d'un instantané. Le callback
et les data
(s'ils sont fournis) seront sérialisés dans l'instantané. Ils peuvent être utilisés pour réinitialiser l'état de l'application ou pour réacquérir les ressources dont l'application a besoin lorsque l'application est redémarrée à partir de l'instantané.
Les callbacks sont exécutés dans l'ordre dans lequel ils sont ajoutés.
v8.startupSnapshot.setDeserializeMainFunction(callback[, data])
Ajoutée dans : v18.6.0, v16.17.0
callback
<Function> Callback à invoquer comme point d'entrée après la désérialisation de l'instantané.data
<any> Données optionnelles qui seront transmises aucallback
lorsqu'il sera appelé.
Définit le point d'entrée de l'application Node.js lorsqu'elle est désérialisée à partir d'un instantané. Ceci ne peut être appelé qu'une seule fois dans le script de création de l'instantané. S'il est appelé, l'application désérialisée n'a plus besoin d'un script de point d'entrée supplémentaire pour démarrer et invoquera simplement le callback avec les données désérialisées (si elles sont fournies). Sinon, un script de point d'entrée doit toujours être fourni à l'application désérialisée.
v8.startupSnapshot.isBuildingSnapshot()
Ajoutée dans : v18.6.0, v16.17.0
- Retourne : <boolean>
Renvoie true si l'instance Node.js est exécutée pour créer un instantané.
Classe : v8.GCProfiler
Ajoutée dans : v19.6.0, v18.15.0
Cette API collecte les données GC dans le thread courant.
new v8.GCProfiler()
Ajoutée dans : v19.6.0, v18.15.0
Crée une nouvelle instance de la classe v8.GCProfiler
.
profiler.start()
Ajoutée dans : v19.6.0, v18.15.0
Démarre la collecte des données GC.
profiler.stop()
Ajoutée dans : v19.6.0, v18.15.0
Arrête la collecte des données GC et renvoie un objet. Le contenu de l'objet est le suivant.
{
"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
}
Voici un exemple.
const { GCProfiler } = require('node:v8');
const profiler = new GCProfiler();
profiler.start();
setTimeout(() => {
console.log(profiler.stop());
}, 1000);