1# V8 2 3<!--introduced_in=v4.0.0--> 4 5<!-- source_link=lib/v8.js --> 6 7The `node:v8` module exposes APIs that are specific to the version of [V8][] 8built into the Node.js binary. It can be accessed using: 9 10```js 11const v8 = require('node:v8'); 12``` 13 14## `v8.cachedDataVersionTag()` 15 16<!-- YAML 17added: v8.0.0 18--> 19 20* Returns: {integer} 21 22Returns an integer representing a version tag derived from the V8 version, 23command-line flags, and detected CPU features. This is useful for determining 24whether a [`vm.Script`][] `cachedData` buffer is compatible with this instance 25of V8. 26 27```js 28console.log(v8.cachedDataVersionTag()); // 3947234607 29// The value returned by v8.cachedDataVersionTag() is derived from the V8 30// version, command-line flags, and detected CPU features. Test that the value 31// does indeed update when flags are toggled. 32v8.setFlagsFromString('--allow_natives_syntax'); 33console.log(v8.cachedDataVersionTag()); // 183726201 34``` 35 36## `v8.getHeapCodeStatistics()` 37 38<!-- YAML 39added: v12.8.0 40--> 41 42* Returns: {Object} 43 44Get statistics about code and its metadata in the heap, see V8 45[`GetHeapCodeAndMetadataStatistics`][] API. Returns an object with the 46following properties: 47 48* `code_and_metadata_size` {number} 49* `bytecode_and_metadata_size` {number} 50* `external_script_source_size` {number} 51* `cpu_profiler_metadata_size` {number} 52 53<!-- eslint-skip --> 54 55```js 56{ 57 code_and_metadata_size: 212208, 58 bytecode_and_metadata_size: 161368, 59 external_script_source_size: 1410794, 60 cpu_profiler_metadata_size: 0, 61} 62``` 63 64## `v8.getHeapSnapshot()` 65 66<!-- YAML 67added: v11.13.0 68--> 69 70* Returns: {stream.Readable} A Readable Stream containing the V8 heap snapshot 71 72Generates a snapshot of the current V8 heap and returns a Readable 73Stream that may be used to read the JSON serialized representation. 74This JSON stream format is intended to be used with tools such as 75Chrome DevTools. The JSON schema is undocumented and specific to the 76V8 engine. Therefore, the schema may change from one version of V8 to the next. 77 78Creating a heap snapshot requires memory about twice the size of the heap at 79the time the snapshot is created. This results in the risk of OOM killers 80terminating the process. 81 82Generating a snapshot is a synchronous operation which blocks the event loop 83for a duration depending on the heap size. 84 85```js 86// Print heap snapshot to the console 87const v8 = require('node:v8'); 88const stream = v8.getHeapSnapshot(); 89stream.pipe(process.stdout); 90``` 91 92## `v8.getHeapSpaceStatistics()` 93 94<!-- YAML 95added: v6.0.0 96changes: 97 - version: v7.5.0 98 pr-url: https://github.com/nodejs/node/pull/10186 99 description: Support values exceeding the 32-bit unsigned integer range. 100--> 101 102* Returns: {Object\[]} 103 104Returns statistics about the V8 heap spaces, i.e. the segments which make up 105the V8 heap. Neither the ordering of heap spaces, nor the availability of a 106heap space can be guaranteed as the statistics are provided via the V8 107[`GetHeapSpaceStatistics`][] function and may change from one V8 version to the 108next. 109 110The value returned is an array of objects containing the following properties: 111 112* `space_name` {string} 113* `space_size` {number} 114* `space_used_size` {number} 115* `space_available_size` {number} 116* `physical_space_size` {number} 117 118```json 119[ 120 { 121 "space_name": "new_space", 122 "space_size": 2063872, 123 "space_used_size": 951112, 124 "space_available_size": 80824, 125 "physical_space_size": 2063872 126 }, 127 { 128 "space_name": "old_space", 129 "space_size": 3090560, 130 "space_used_size": 2493792, 131 "space_available_size": 0, 132 "physical_space_size": 3090560 133 }, 134 { 135 "space_name": "code_space", 136 "space_size": 1260160, 137 "space_used_size": 644256, 138 "space_available_size": 960, 139 "physical_space_size": 1260160 140 }, 141 { 142 "space_name": "map_space", 143 "space_size": 1094160, 144 "space_used_size": 201608, 145 "space_available_size": 0, 146 "physical_space_size": 1094160 147 }, 148 { 149 "space_name": "large_object_space", 150 "space_size": 0, 151 "space_used_size": 0, 152 "space_available_size": 1490980608, 153 "physical_space_size": 0 154 } 155] 156``` 157 158## `v8.getHeapStatistics()` 159 160<!-- YAML 161added: v1.0.0 162changes: 163 - version: v7.5.0 164 pr-url: https://github.com/nodejs/node/pull/10186 165 description: Support values exceeding the 32-bit unsigned integer range. 166 - version: v7.2.0 167 pr-url: https://github.com/nodejs/node/pull/8610 168 description: Added `malloced_memory`, `peak_malloced_memory`, 169 and `does_zap_garbage`. 170--> 171 172* Returns: {Object} 173 174Returns an object with the following properties: 175 176* `total_heap_size` {number} 177* `total_heap_size_executable` {number} 178* `total_physical_size` {number} 179* `total_available_size` {number} 180* `used_heap_size` {number} 181* `heap_size_limit` {number} 182* `malloced_memory` {number} 183* `peak_malloced_memory` {number} 184* `does_zap_garbage` {number} 185* `number_of_native_contexts` {number} 186* `number_of_detached_contexts` {number} 187* `total_global_handles_size` {number} 188* `used_global_handles_size` {number} 189* `external_memory` {number} 190 191`does_zap_garbage` is a 0/1 boolean, which signifies whether the 192`--zap_code_space` option is enabled or not. This makes V8 overwrite heap 193garbage with a bit pattern. The RSS footprint (resident set size) gets bigger 194because it continuously touches all heap pages and that makes them less likely 195to get swapped out by the operating system. 196 197`number_of_native_contexts` The value of native\_context is the number of the 198top-level contexts currently active. Increase of this number over time indicates 199a memory leak. 200 201`number_of_detached_contexts` The value of detached\_context is the number 202of contexts that were detached and not yet garbage collected. This number 203being non-zero indicates a potential memory leak. 204 205`total_global_handles_size` The value of total\_global\_handles\_size is the 206total memory size of V8 global handles. 207 208`used_global_handles_size` The value of used\_global\_handles\_size is the 209used memory size of V8 global handles. 210 211`external_memory` The value of external\_memory is the memory size of array 212buffers and external strings. 213 214<!-- eslint-skip --> 215 216```js 217{ 218 total_heap_size: 7326976, 219 total_heap_size_executable: 4194304, 220 total_physical_size: 7326976, 221 total_available_size: 1152656, 222 used_heap_size: 3476208, 223 heap_size_limit: 1535115264, 224 malloced_memory: 16384, 225 peak_malloced_memory: 1127496, 226 does_zap_garbage: 0, 227 number_of_native_contexts: 1, 228 number_of_detached_contexts: 0, 229 total_global_handles_size: 8192, 230 used_global_handles_size: 3296, 231 external_memory: 318824 232} 233``` 234 235## `v8.setFlagsFromString(flags)` 236 237<!-- YAML 238added: v1.0.0 239--> 240 241* `flags` {string} 242 243The `v8.setFlagsFromString()` method can be used to programmatically set 244V8 command-line flags. This method should be used with care. Changing settings 245after the VM has started may result in unpredictable behavior, including 246crashes and data loss; or it may simply do nothing. 247 248The V8 options available for a version of Node.js may be determined by running 249`node --v8-options`. 250 251Usage: 252 253```js 254// Print GC events to stdout for one minute. 255const v8 = require('node:v8'); 256v8.setFlagsFromString('--trace_gc'); 257setTimeout(() => { v8.setFlagsFromString('--notrace_gc'); }, 60e3); 258``` 259 260## `v8.stopCoverage()` 261 262<!-- YAML 263added: 264 - v15.1.0 265 - v14.18.0 266 - v12.22.0 267--> 268 269The `v8.stopCoverage()` method allows the user to stop the coverage collection 270started by [`NODE_V8_COVERAGE`][], so that V8 can release the execution count 271records and optimize code. This can be used in conjunction with 272[`v8.takeCoverage()`][] if the user wants to collect the coverage on demand. 273 274## `v8.takeCoverage()` 275 276<!-- YAML 277added: 278 - v15.1.0 279 - v14.18.0 280 - v12.22.0 281--> 282 283The `v8.takeCoverage()` method allows the user to write the coverage started by 284[`NODE_V8_COVERAGE`][] to disk on demand. This method can be invoked multiple 285times during the lifetime of the process. Each time the execution counter will 286be reset and a new coverage report will be written to the directory specified 287by [`NODE_V8_COVERAGE`][]. 288 289When the process is about to exit, one last coverage will still be written to 290disk unless [`v8.stopCoverage()`][] is invoked before the process exits. 291 292## `v8.writeHeapSnapshot([filename])` 293 294<!-- YAML 295added: v11.13.0 296changes: 297 - version: v18.0.0 298 pr-url: https://github.com/nodejs/node/pull/41373 299 description: An exception will now be thrown if the file could not be written. 300 - version: v18.0.0 301 pr-url: https://github.com/nodejs/node/pull/42577 302 description: Make the returned error codes consistent across all platforms. 303--> 304 305* `filename` {string} The file path where the V8 heap snapshot is to be 306 saved. If not specified, a file name with the pattern 307 `'Heap-${yyyymmdd}-${hhmmss}-${pid}-${thread_id}.heapsnapshot'` will be 308 generated, where `{pid}` will be the PID of the Node.js process, 309 `{thread_id}` will be `0` when `writeHeapSnapshot()` is called from 310 the main Node.js thread or the id of a worker thread. 311* Returns: {string} The filename where the snapshot was saved. 312 313Generates a snapshot of the current V8 heap and writes it to a JSON 314file. This file is intended to be used with tools such as Chrome 315DevTools. The JSON schema is undocumented and specific to the V8 316engine, and may change from one version of V8 to the next. 317 318A heap snapshot is specific to a single V8 isolate. When using 319[worker threads][], a heap snapshot generated from the main thread will 320not contain any information about the workers, and vice versa. 321 322Creating a heap snapshot requires memory about twice the size of the heap at 323the time the snapshot is created. This results in the risk of OOM killers 324terminating the process. 325 326Generating a snapshot is a synchronous operation which blocks the event loop 327for a duration depending on the heap size. 328 329```js 330const { writeHeapSnapshot } = require('node:v8'); 331const { 332 Worker, 333 isMainThread, 334 parentPort, 335} = require('node:worker_threads'); 336 337if (isMainThread) { 338 const worker = new Worker(__filename); 339 340 worker.once('message', (filename) => { 341 console.log(`worker heapdump: ${filename}`); 342 // Now get a heapdump for the main thread. 343 console.log(`main thread heapdump: ${writeHeapSnapshot()}`); 344 }); 345 346 // Tell the worker to create a heapdump. 347 worker.postMessage('heapdump'); 348} else { 349 parentPort.once('message', (message) => { 350 if (message === 'heapdump') { 351 // Generate a heapdump for the worker 352 // and return the filename to the parent. 353 parentPort.postMessage(writeHeapSnapshot()); 354 } 355 }); 356} 357``` 358 359## `v8.setHeapSnapshotNearHeapLimit(limit)` 360 361<!-- YAML 362added: v18.10.0 363--> 364 365> Stability: 1 - Experimental 366 367* `limit` {integer} 368 369The API is a no-op if `--heapsnapshot-near-heap-limit` is already set from the 370command line or the API is called more than once. `limit` must be a positive 371integer. See [`--heapsnapshot-near-heap-limit`][] for more information. 372 373## Serialization API 374 375The serialization API provides means of serializing JavaScript values in a way 376that is compatible with the [HTML structured clone algorithm][]. 377 378The format is backward-compatible (i.e. safe to store to disk). 379Equal JavaScript values may result in different serialized output. 380 381### `v8.serialize(value)` 382 383<!-- YAML 384added: v8.0.0 385--> 386 387* `value` {any} 388* Returns: {Buffer} 389 390Uses a [`DefaultSerializer`][] to serialize `value` into a buffer. 391 392[`ERR_BUFFER_TOO_LARGE`][] will be thrown when trying to 393serialize a huge object which requires buffer 394larger than [`buffer.constants.MAX_LENGTH`][]. 395 396### `v8.deserialize(buffer)` 397 398<!-- YAML 399added: v8.0.0 400--> 401 402* `buffer` {Buffer|TypedArray|DataView} A buffer returned by [`serialize()`][]. 403 404Uses a [`DefaultDeserializer`][] with default options to read a JS value 405from a buffer. 406 407### Class: `v8.Serializer` 408 409<!-- YAML 410added: v8.0.0 411--> 412 413#### `new Serializer()` 414 415Creates a new `Serializer` object. 416 417#### `serializer.writeHeader()` 418 419Writes out a header, which includes the serialization format version. 420 421#### `serializer.writeValue(value)` 422 423* `value` {any} 424 425Serializes a JavaScript value and adds the serialized representation to the 426internal buffer. 427 428This throws an error if `value` cannot be serialized. 429 430#### `serializer.releaseBuffer()` 431 432* Returns: {Buffer} 433 434Returns the stored internal buffer. This serializer should not be used once 435the buffer is released. Calling this method results in undefined behavior 436if a previous write has failed. 437 438#### `serializer.transferArrayBuffer(id, arrayBuffer)` 439 440* `id` {integer} A 32-bit unsigned integer. 441* `arrayBuffer` {ArrayBuffer} An `ArrayBuffer` instance. 442 443Marks an `ArrayBuffer` as having its contents transferred out of band. 444Pass the corresponding `ArrayBuffer` in the deserializing context to 445[`deserializer.transferArrayBuffer()`][]. 446 447#### `serializer.writeUint32(value)` 448 449* `value` {integer} 450 451Write a raw 32-bit unsigned integer. 452For use inside of a custom [`serializer._writeHostObject()`][]. 453 454#### `serializer.writeUint64(hi, lo)` 455 456* `hi` {integer} 457* `lo` {integer} 458 459Write a raw 64-bit unsigned integer, split into high and low 32-bit parts. 460For use inside of a custom [`serializer._writeHostObject()`][]. 461 462#### `serializer.writeDouble(value)` 463 464* `value` {number} 465 466Write a JS `number` value. 467For use inside of a custom [`serializer._writeHostObject()`][]. 468 469#### `serializer.writeRawBytes(buffer)` 470 471* `buffer` {Buffer|TypedArray|DataView} 472 473Write raw bytes into the serializer's internal buffer. The deserializer 474will require a way to compute the length of the buffer. 475For use inside of a custom [`serializer._writeHostObject()`][]. 476 477#### `serializer._writeHostObject(object)` 478 479* `object` {Object} 480 481This method is called to write some kind of host object, i.e. an object created 482by native C++ bindings. If it is not possible to serialize `object`, a suitable 483exception should be thrown. 484 485This method is not present on the `Serializer` class itself but can be provided 486by subclasses. 487 488#### `serializer._getDataCloneError(message)` 489 490* `message` {string} 491 492This method is called to generate error objects that will be thrown when an 493object can not be cloned. 494 495This method defaults to the [`Error`][] constructor and can be overridden on 496subclasses. 497 498#### `serializer._getSharedArrayBufferId(sharedArrayBuffer)` 499 500* `sharedArrayBuffer` {SharedArrayBuffer} 501 502This method is called when the serializer is going to serialize a 503`SharedArrayBuffer` object. It must return an unsigned 32-bit integer ID for 504the object, using the same ID if this `SharedArrayBuffer` has already been 505serialized. When deserializing, this ID will be passed to 506[`deserializer.transferArrayBuffer()`][]. 507 508If the object cannot be serialized, an exception should be thrown. 509 510This method is not present on the `Serializer` class itself but can be provided 511by subclasses. 512 513#### `serializer._setTreatArrayBufferViewsAsHostObjects(flag)` 514 515* `flag` {boolean} **Default:** `false` 516 517Indicate whether to treat `TypedArray` and `DataView` objects as 518host objects, i.e. pass them to [`serializer._writeHostObject()`][]. 519 520### Class: `v8.Deserializer` 521 522<!-- YAML 523added: v8.0.0 524--> 525 526#### `new Deserializer(buffer)` 527 528* `buffer` {Buffer|TypedArray|DataView} A buffer returned by 529 [`serializer.releaseBuffer()`][]. 530 531Creates a new `Deserializer` object. 532 533#### `deserializer.readHeader()` 534 535Reads and validates a header (including the format version). 536May, for example, reject an invalid or unsupported wire format. In that case, 537an `Error` is thrown. 538 539#### `deserializer.readValue()` 540 541Deserializes a JavaScript value from the buffer and returns it. 542 543#### `deserializer.transferArrayBuffer(id, arrayBuffer)` 544 545* `id` {integer} A 32-bit unsigned integer. 546* `arrayBuffer` {ArrayBuffer|SharedArrayBuffer} An `ArrayBuffer` instance. 547 548Marks an `ArrayBuffer` as having its contents transferred out of band. 549Pass the corresponding `ArrayBuffer` in the serializing context to 550[`serializer.transferArrayBuffer()`][] (or return the `id` from 551[`serializer._getSharedArrayBufferId()`][] in the case of `SharedArrayBuffer`s). 552 553#### `deserializer.getWireFormatVersion()` 554 555* Returns: {integer} 556 557Reads the underlying wire format version. Likely mostly to be useful to 558legacy code reading old wire format versions. May not be called before 559`.readHeader()`. 560 561#### `deserializer.readUint32()` 562 563* Returns: {integer} 564 565Read a raw 32-bit unsigned integer and return it. 566For use inside of a custom [`deserializer._readHostObject()`][]. 567 568#### `deserializer.readUint64()` 569 570* Returns: {integer\[]} 571 572Read a raw 64-bit unsigned integer and return it as an array `[hi, lo]` 573with two 32-bit unsigned integer entries. 574For use inside of a custom [`deserializer._readHostObject()`][]. 575 576#### `deserializer.readDouble()` 577 578* Returns: {number} 579 580Read a JS `number` value. 581For use inside of a custom [`deserializer._readHostObject()`][]. 582 583#### `deserializer.readRawBytes(length)` 584 585* `length` {integer} 586* Returns: {Buffer} 587 588Read raw bytes from the deserializer's internal buffer. The `length` parameter 589must correspond to the length of the buffer that was passed to 590[`serializer.writeRawBytes()`][]. 591For use inside of a custom [`deserializer._readHostObject()`][]. 592 593#### `deserializer._readHostObject()` 594 595This method is called to read some kind of host object, i.e. an object that is 596created by native C++ bindings. If it is not possible to deserialize the data, 597a suitable exception should be thrown. 598 599This method is not present on the `Deserializer` class itself but can be 600provided by subclasses. 601 602### Class: `v8.DefaultSerializer` 603 604<!-- YAML 605added: v8.0.0 606--> 607 608A subclass of [`Serializer`][] that serializes `TypedArray` 609(in particular [`Buffer`][]) and `DataView` objects as host objects, and only 610stores the part of their underlying `ArrayBuffer`s that they are referring to. 611 612### Class: `v8.DefaultDeserializer` 613 614<!-- YAML 615added: v8.0.0 616--> 617 618A subclass of [`Deserializer`][] corresponding to the format written by 619[`DefaultSerializer`][]. 620 621## Promise hooks 622 623The `promiseHooks` interface can be used to track promise lifecycle events. 624To track _all_ async activity, see [`async_hooks`][] which internally uses this 625module to produce promise lifecycle events in addition to events for other 626async resources. For request context management, see [`AsyncLocalStorage`][]. 627 628```mjs 629import { promiseHooks } from 'node:v8'; 630 631// There are four lifecycle events produced by promises: 632 633// The `init` event represents the creation of a promise. This could be a 634// direct creation such as with `new Promise(...)` or a continuation such 635// as `then()` or `catch()`. It also happens whenever an async function is 636// called or does an `await`. If a continuation promise is created, the 637// `parent` will be the promise it is a continuation from. 638function init(promise, parent) { 639 console.log('a promise was created', { promise, parent }); 640} 641 642// The `settled` event happens when a promise receives a resolution or 643// rejection value. This may happen synchronously such as when using 644// `Promise.resolve()` on non-promise input. 645function settled(promise) { 646 console.log('a promise resolved or rejected', { promise }); 647} 648 649// The `before` event runs immediately before a `then()` or `catch()` handler 650// runs or an `await` resumes execution. 651function before(promise) { 652 console.log('a promise is about to call a then handler', { promise }); 653} 654 655// The `after` event runs immediately after a `then()` handler runs or when 656// an `await` begins after resuming from another. 657function after(promise) { 658 console.log('a promise is done calling a then handler', { promise }); 659} 660 661// Lifecycle hooks may be started and stopped individually 662const stopWatchingInits = promiseHooks.onInit(init); 663const stopWatchingSettleds = promiseHooks.onSettled(settled); 664const stopWatchingBefores = promiseHooks.onBefore(before); 665const stopWatchingAfters = promiseHooks.onAfter(after); 666 667// Or they may be started and stopped in groups 668const stopHookSet = promiseHooks.createHook({ 669 init, 670 settled, 671 before, 672 after, 673}); 674 675// To stop a hook, call the function returned at its creation. 676stopWatchingInits(); 677stopWatchingSettleds(); 678stopWatchingBefores(); 679stopWatchingAfters(); 680stopHookSet(); 681``` 682 683### `promiseHooks.onInit(init)` 684 685<!-- YAML 686added: 687 - v17.1.0 688 - v16.14.0 689--> 690 691* `init` {Function} The [`init` callback][] to call when a promise is created. 692* Returns: {Function} Call to stop the hook. 693 694**The `init` hook must be a plain function. Providing an async function will 695throw as it would produce an infinite microtask loop.** 696 697```mjs 698import { promiseHooks } from 'node:v8'; 699 700const stop = promiseHooks.onInit((promise, parent) => {}); 701``` 702 703```cjs 704const { promiseHooks } = require('node:v8'); 705 706const stop = promiseHooks.onInit((promise, parent) => {}); 707``` 708 709### `promiseHooks.onSettled(settled)` 710 711<!-- YAML 712added: 713 - v17.1.0 714 - v16.14.0 715--> 716 717* `settled` {Function} The [`settled` callback][] to call when a promise 718 is resolved or rejected. 719* Returns: {Function} Call to stop the hook. 720 721**The `settled` hook must be a plain function. Providing an async function will 722throw as it would produce an infinite microtask loop.** 723 724```mjs 725import { promiseHooks } from 'node:v8'; 726 727const stop = promiseHooks.onSettled((promise) => {}); 728``` 729 730```cjs 731const { promiseHooks } = require('node:v8'); 732 733const stop = promiseHooks.onSettled((promise) => {}); 734``` 735 736### `promiseHooks.onBefore(before)` 737 738<!-- YAML 739added: 740 - v17.1.0 741 - v16.14.0 742--> 743 744* `before` {Function} The [`before` callback][] to call before a promise 745 continuation executes. 746* Returns: {Function} Call to stop the hook. 747 748**The `before` hook must be a plain function. Providing an async function will 749throw as it would produce an infinite microtask loop.** 750 751```mjs 752import { promiseHooks } from 'node:v8'; 753 754const stop = promiseHooks.onBefore((promise) => {}); 755``` 756 757```cjs 758const { promiseHooks } = require('node:v8'); 759 760const stop = promiseHooks.onBefore((promise) => {}); 761``` 762 763### `promiseHooks.onAfter(after)` 764 765<!-- YAML 766added: 767 - v17.1.0 768 - v16.14.0 769--> 770 771* `after` {Function} The [`after` callback][] to call after a promise 772 continuation executes. 773* Returns: {Function} Call to stop the hook. 774 775**The `after` hook must be a plain function. Providing an async function will 776throw as it would produce an infinite microtask loop.** 777 778```mjs 779import { promiseHooks } from 'node:v8'; 780 781const stop = promiseHooks.onAfter((promise) => {}); 782``` 783 784```cjs 785const { promiseHooks } = require('node:v8'); 786 787const stop = promiseHooks.onAfter((promise) => {}); 788``` 789 790### `promiseHooks.createHook(callbacks)` 791 792<!-- YAML 793added: 794 - v17.1.0 795 - v16.14.0 796--> 797 798* `callbacks` {Object} The [Hook Callbacks][] to register 799 * `init` {Function} The [`init` callback][]. 800 * `before` {Function} The [`before` callback][]. 801 * `after` {Function} The [`after` callback][]. 802 * `settled` {Function} The [`settled` callback][]. 803* Returns: {Function} Used for disabling hooks 804 805**The hook callbacks must be plain functions. Providing async functions will 806throw as it would produce an infinite microtask loop.** 807 808Registers functions to be called for different lifetime events of each promise. 809 810The callbacks `init()`/`before()`/`after()`/`settled()` are called for the 811respective events during a promise's lifetime. 812 813All callbacks are optional. For example, if only promise creation needs to 814be tracked, then only the `init` callback needs to be passed. The 815specifics of all functions that can be passed to `callbacks` is in the 816[Hook Callbacks][] section. 817 818```mjs 819import { promiseHooks } from 'node:v8'; 820 821const stopAll = promiseHooks.createHook({ 822 init(promise, parent) {}, 823}); 824``` 825 826```cjs 827const { promiseHooks } = require('node:v8'); 828 829const stopAll = promiseHooks.createHook({ 830 init(promise, parent) {}, 831}); 832``` 833 834### Hook callbacks 835 836Key events in the lifetime of a promise have been categorized into four areas: 837creation of a promise, before/after a continuation handler is called or around 838an await, and when the promise resolves or rejects. 839 840While these hooks are similar to those of [`async_hooks`][] they lack a 841`destroy` hook. Other types of async resources typically represent sockets or 842file descriptors which have a distinct "closed" state to express the `destroy` 843lifecycle event while promises remain usable for as long as code can still 844reach them. Garbage collection tracking is used to make promises fit into the 845`async_hooks` event model, however this tracking is very expensive and they may 846not necessarily ever even be garbage collected. 847 848Because promises are asynchronous resources whose lifecycle is tracked 849via the promise hooks mechanism, the `init()`, `before()`, `after()`, and 850`settled()` callbacks _must not_ be async functions as they create more 851promises which would produce an infinite loop. 852 853While this API is used to feed promise events into [`async_hooks`][], the 854ordering between the two is undefined. Both APIs are multi-tenant 855and therefore could produce events in any order relative to each other. 856 857#### `init(promise, parent)` 858 859* `promise` {Promise} The promise being created. 860* `parent` {Promise} The promise continued from, if applicable. 861 862Called when a promise is constructed. This _does not_ mean that corresponding 863`before`/`after` events will occur, only that the possibility exists. This will 864happen if a promise is created without ever getting a continuation. 865 866#### `before(promise)` 867 868* `promise` {Promise} 869 870Called before a promise continuation executes. This can be in the form of 871`then()`, `catch()`, or `finally()` handlers or an `await` resuming. 872 873The `before` callback will be called 0 to N times. The `before` callback 874will typically be called 0 times if no continuation was ever made for the 875promise. The `before` callback may be called many times in the case where 876many continuations have been made from the same promise. 877 878#### `after(promise)` 879 880* `promise` {Promise} 881 882Called immediately after a promise continuation executes. This may be after a 883`then()`, `catch()`, or `finally()` handler or before an `await` after another 884`await`. 885 886#### `settled(promise)` 887 888* `promise` {Promise} 889 890Called when the promise receives a resolution or rejection value. This may 891occur synchronously in the case of `Promise.resolve()` or `Promise.reject()`. 892 893## Startup Snapshot API 894 895<!-- YAML 896added: v18.6.0 897--> 898 899> Stability: 1 - Experimental 900 901The `v8.startupSnapshot` interface can be used to add serialization and 902deserialization hooks for custom startup snapshots. 903 904```console 905$ node --snapshot-blob snapshot.blob --build-snapshot entry.js 906# This launches a process with the snapshot 907$ node --snapshot-blob snapshot.blob 908``` 909 910In the example above, `entry.js` can use methods from the `v8.startupSnapshot` 911interface to specify how to save information for custom objects in the snapshot 912during serialization and how the information can be used to synchronize these 913objects during deserialization of the snapshot. For example, if the `entry.js` 914contains the following script: 915 916```cjs 917'use strict'; 918 919const fs = require('node:fs'); 920const zlib = require('node:zlib'); 921const path = require('node:path'); 922const assert = require('node:assert'); 923 924const v8 = require('node:v8'); 925 926class BookShelf { 927 storage = new Map(); 928 929 // Reading a series of files from directory and store them into storage. 930 constructor(directory, books) { 931 for (const book of books) { 932 this.storage.set(book, fs.readFileSync(path.join(directory, book))); 933 } 934 } 935 936 static compressAll(shelf) { 937 for (const [ book, content ] of shelf.storage) { 938 shelf.storage.set(book, zlib.gzipSync(content)); 939 } 940 } 941 942 static decompressAll(shelf) { 943 for (const [ book, content ] of shelf.storage) { 944 shelf.storage.set(book, zlib.gunzipSync(content)); 945 } 946 } 947} 948 949// __dirname here is where the snapshot script is placed 950// during snapshot building time. 951const shelf = new BookShelf(__dirname, [ 952 'book1.en_US.txt', 953 'book1.es_ES.txt', 954 'book2.zh_CN.txt', 955]); 956 957assert(v8.startupSnapshot.isBuildingSnapshot()); 958// On snapshot serialization, compress the books to reduce size. 959v8.startupSnapshot.addSerializeCallback(BookShelf.compressAll, shelf); 960// On snapshot deserialization, decompress the books. 961v8.startupSnapshot.addDeserializeCallback(BookShelf.decompressAll, shelf); 962v8.startupSnapshot.setDeserializeMainFunction((shelf) => { 963 // process.env and process.argv are refreshed during snapshot 964 // deserialization. 965 const lang = process.env.BOOK_LANG || 'en_US'; 966 const book = process.argv[1]; 967 const name = `${book}.${lang}.txt`; 968 console.log(shelf.storage.get(name)); 969}, shelf); 970``` 971 972The resulted binary will get print the data deserialized from the snapshot 973during start up, using the refreshed `process.env` and `process.argv` of 974the launched process: 975 976```console 977$ BOOK_LANG=es_ES node --snapshot-blob snapshot.blob book1 978# Prints content of book1.es_ES.txt deserialized from the snapshot. 979``` 980 981Currently the application deserialized from a user-land snapshot cannot 982be snapshotted again, so these APIs are only available to applications 983that are not deserialized from a user-land snapshot. 984 985### `v8.startupSnapshot.addSerializeCallback(callback[, data])` 986 987<!-- YAML 988added: v18.6.0 989--> 990 991* `callback` {Function} Callback to be invoked before serialization. 992* `data` {any} Optional data that will be passed to the `callback` when it 993 gets called. 994 995Add a callback that will be called when the Node.js instance is about to 996get serialized into a snapshot and exit. This can be used to release 997resources that should not or cannot be serialized or to convert user data 998into a form more suitable for serialization. 999 1000### `v8.startupSnapshot.addDeserializeCallback(callback[, data])` 1001 1002<!-- YAML 1003added: v18.6.0 1004--> 1005 1006* `callback` {Function} Callback to be invoked after the snapshot is 1007 deserialized. 1008* `data` {any} Optional data that will be passed to the `callback` when it 1009 gets called. 1010 1011Add a callback that will be called when the Node.js instance is deserialized 1012from a snapshot. The `callback` and the `data` (if provided) will be 1013serialized into the snapshot, they can be used to re-initialize the state 1014of the application or to re-acquire resources that the application needs 1015when the application is restarted from the snapshot. 1016 1017### `v8.startupSnapshot.setDeserializeMainFunction(callback[, data])` 1018 1019<!-- YAML 1020added: v18.6.0 1021--> 1022 1023* `callback` {Function} Callback to be invoked as the entry point after the 1024 snapshot is deserialized. 1025* `data` {any} Optional data that will be passed to the `callback` when it 1026 gets called. 1027 1028This sets the entry point of the Node.js application when it is deserialized 1029from a snapshot. This can be called only once in the snapshot building 1030script. If called, the deserialized application no longer needs an additional 1031entry point script to start up and will simply invoke the callback along with 1032the deserialized data (if provided), otherwise an entry point script still 1033needs to be provided to the deserialized application. 1034 1035### `v8.startupSnapshot.isBuildingSnapshot()` 1036 1037<!-- YAML 1038added: v18.6.0 1039--> 1040 1041* Returns: {boolean} 1042 1043Returns true if the Node.js instance is run to build a snapshot. 1044 1045## Class: `v8.GCProfiler` 1046 1047<!-- YAML 1048added: v18.15.0 1049--> 1050 1051This API collects GC data in current thread. 1052 1053### `new v8.GCProfiler()` 1054 1055<!-- YAML 1056added: v18.15.0 1057--> 1058 1059Create a new instance of the `v8.GCProfiler` class. 1060 1061### `profiler.start()` 1062 1063<!-- YAML 1064added: v18.15.0 1065--> 1066 1067Start collecting GC data. 1068 1069### `profiler.stop()` 1070 1071<!-- YAML 1072added: v18.15.0 1073--> 1074 1075Stop collecting GC data and return an object.The content of object 1076is as follows. 1077 1078```json 1079{ 1080 "version": 1, 1081 "startTime": 1674059033862, 1082 "statistics": [ 1083 { 1084 "gcType": "Scavenge", 1085 "beforeGC": { 1086 "heapStatistics": { 1087 "totalHeapSize": 5005312, 1088 "totalHeapSizeExecutable": 524288, 1089 "totalPhysicalSize": 5226496, 1090 "totalAvailableSize": 4341325216, 1091 "totalGlobalHandlesSize": 8192, 1092 "usedGlobalHandlesSize": 2112, 1093 "usedHeapSize": 4883840, 1094 "heapSizeLimit": 4345298944, 1095 "mallocedMemory": 254128, 1096 "externalMemory": 225138, 1097 "peakMallocedMemory": 181760 1098 }, 1099 "heapSpaceStatistics": [ 1100 { 1101 "spaceName": "read_only_space", 1102 "spaceSize": 0, 1103 "spaceUsedSize": 0, 1104 "spaceAvailableSize": 0, 1105 "physicalSpaceSize": 0 1106 } 1107 ] 1108 }, 1109 "cost": 1574.14, 1110 "afterGC": { 1111 "heapStatistics": { 1112 "totalHeapSize": 6053888, 1113 "totalHeapSizeExecutable": 524288, 1114 "totalPhysicalSize": 5500928, 1115 "totalAvailableSize": 4341101384, 1116 "totalGlobalHandlesSize": 8192, 1117 "usedGlobalHandlesSize": 2112, 1118 "usedHeapSize": 4059096, 1119 "heapSizeLimit": 4345298944, 1120 "mallocedMemory": 254128, 1121 "externalMemory": 225138, 1122 "peakMallocedMemory": 181760 1123 }, 1124 "heapSpaceStatistics": [ 1125 { 1126 "spaceName": "read_only_space", 1127 "spaceSize": 0, 1128 "spaceUsedSize": 0, 1129 "spaceAvailableSize": 0, 1130 "physicalSpaceSize": 0 1131 } 1132 ] 1133 } 1134 } 1135 ], 1136 "endTime": 1674059036865 1137} 1138``` 1139 1140Here's an example. 1141 1142```js 1143const { GCProfiler } = require('v8'); 1144const profiler = new GCProfiler(); 1145profiler.start(); 1146setTimeout(() => { 1147 console.log(profiler.stop()); 1148}, 1000); 1149``` 1150 1151[HTML structured clone algorithm]: https://developer.mozilla.org/en-US/docs/Web/API/Web_Workers_API/Structured_clone_algorithm 1152[Hook Callbacks]: #hook-callbacks 1153[V8]: https://developers.google.com/v8/ 1154[`--heapsnapshot-near-heap-limit`]: cli.md#--heapsnapshot-near-heap-limitmax_count 1155[`AsyncLocalStorage`]: async_context.md#class-asynclocalstorage 1156[`Buffer`]: buffer.md 1157[`DefaultDeserializer`]: #class-v8defaultdeserializer 1158[`DefaultSerializer`]: #class-v8defaultserializer 1159[`Deserializer`]: #class-v8deserializer 1160[`ERR_BUFFER_TOO_LARGE`]: errors.md#err_buffer_too_large 1161[`Error`]: errors.md#class-error 1162[`GetHeapCodeAndMetadataStatistics`]: https://v8docs.nodesource.com/node-13.2/d5/dda/classv8_1_1_isolate.html#a6079122af17612ef54ef3348ce170866 1163[`GetHeapSpaceStatistics`]: https://v8docs.nodesource.com/node-13.2/d5/dda/classv8_1_1_isolate.html#ac673576f24fdc7a33378f8f57e1d13a4 1164[`NODE_V8_COVERAGE`]: cli.md#node_v8_coveragedir 1165[`Serializer`]: #class-v8serializer 1166[`after` callback]: #afterpromise 1167[`async_hooks`]: async_hooks.md 1168[`before` callback]: #beforepromise 1169[`buffer.constants.MAX_LENGTH`]: buffer.md#bufferconstantsmax_length 1170[`deserializer._readHostObject()`]: #deserializer_readhostobject 1171[`deserializer.transferArrayBuffer()`]: #deserializertransferarraybufferid-arraybuffer 1172[`init` callback]: #initpromise-parent 1173[`serialize()`]: #v8serializevalue 1174[`serializer._getSharedArrayBufferId()`]: #serializer_getsharedarraybufferidsharedarraybuffer 1175[`serializer._writeHostObject()`]: #serializer_writehostobjectobject 1176[`serializer.releaseBuffer()`]: #serializerreleasebuffer 1177[`serializer.transferArrayBuffer()`]: #serializertransferarraybufferid-arraybuffer 1178[`serializer.writeRawBytes()`]: #serializerwriterawbytesbuffer 1179[`settled` callback]: #settledpromise 1180[`v8.stopCoverage()`]: #v8stopcoverage 1181[`v8.takeCoverage()`]: #v8takecoverage 1182[`vm.Script`]: vm.md#new-vmscriptcode-options 1183[worker threads]: worker_threads.md 1184