V8
Исходный код: lib/v8.js
Модуль node:v8 предоставляет API, специфичные для версии V8, встроенной в бинарник Node.js. К нему можно получить доступ, используя:
const v8 = require('node:v8'); copy
v8.cachedDataVersionTag()
- Возвращает: <целое число>
Возвращает целое число, представляющее тег версии, полученный из версии V8, флагов командной строки и обнаруженных функций процессора. Это полезно для определения совместимости буфера vm.Script cachedData с этим экземпляром V8.
console.log(v8.cachedDataVersionTag()); // 3947234607
// The value returned by v8.cachedDataVersionTag() is derived from the V8
// version, command-line flags, and detected CPU features. Test that the value
// does indeed update when flags are toggled.
v8.setFlagsFromString('--allow_natives_syntax');
console.log(v8.cachedDataVersionTag()); // 183726201 copy
v8.getHeapCodeStatistics()
- Возвращает: <объект>
Получить статистику о коде и его метаданных в куче, см. API V8 GetHeapCodeAndMetadataStatistics. Возвращает объект со следующими свойствами:
-
code_and_metadata_size<число> -
bytecode_and_metadata_size<число> -
external_script_source_size<число> -
cpu_profiler_metadata_size<число>
{
code_and_metadata_size: 212208,
bytecode_and_metadata_size: 161368,
external_script_source_size: 1410794,
cpu_profiler_metadata_size: 0,
} copy
v8.getHeapSnapshot([options])
-
options<объект>-
exposeInternals<логическое значение> Если true, отобразить внутренние данные в снимке кучи. По умолчанию:false. -
exposeNumericValues<логическое значение> Если true, отобразить числовые значения в искусственных полях. По умолчанию:false.
-
-
Возвращает: <stream.Readable> Поток Readable, содержащий снимок кучи V8.
Создаёт снимок текущей кучи V8 и возвращает поток Readable, который может быть использован для чтения сериализованного в JSON представления. Этот формат JSON предназначен для использования с такими инструментами, как Chrome DevTools. Схема JSON не документирована и специфична для движка V8. Поэтому она может меняться от одной версии V8 к другой.
Создание снимка кучи требует памяти примерно в два раза больше, чем размер кучи в момент создания снимка. Это влечёт риск завершения процесса из-за ошибки OOM.
Генерация снимка — синхронная операция, которая блокирует цикл событий на время, зависящее от размера кучи.
// Print heap snapshot to the console
const v8 = require('node:v8');
const stream = v8.getHeapSnapshot();
stream.pipe(process.stdout); copy
v8.getHeapSpaceStatistics()
- Возвращает: <массив объектов>
Возвращает статистику о пространствах кучи V8, то есть о сегментах, составляющих кучу V8. Порядок пространств кучи и доступность пространства кучи не гарантируются, так как статистика предоставляется через функцию V8 GetHeapSpaceStatistics и может меняться от одной версии V8 к другой.
Возвращаемое значение — массив объектов, содержащих следующие свойства:
-
space_name<строка> -
space_size<число> -
space_used_size<число> -
space_available_size<число> -
physical_space_size<число>
[
{
"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
}
] copy
v8.getHeapStatistics()
- Возвращает: <объект>
Возвращает объект со следующими свойствами:
-
total_heap_size<число> -
total_heap_size_executable<число> -
total_physical_size<число> -
total_available_size<число> -
used_heap_size<число> -
heap_size_limit<число> -
malloced_memory<число> -
peak_malloced_memory<число> -
does_zap_garbage<число> -
number_of_native_contexts<число> -
number_of_detached_contexts<число> -
total_global_handles_size<число> -
used_global_handles_size<число> -
external_memory<число>
does_zap_garbage — булево значение 0/1, которое указывает, включена ли опция --zap_code_space. Это заставляет V8 перезаписывать мусор кучи битовым шаблоном. Следовательно, размер RSS (resident set size) увеличивается, потому что он постоянно обращается ко всем страницам кучи, и это уменьшает вероятность их вытеснения операционной системой.
number_of_native_contexts Значение native_context — количество активных верхнеуровневых контекстов в данный момент. Увеличение этого числа со временем указывает на утечку памяти.
number_of_detached_contexts Значение detached_context — количество контекстов, которые были отделены и ещё не собраны сборщиком мусора. Неноль этого числа указывает на потенциальную утечку памяти.
total_global_handles_size Значение total_global_handles_size — общий размер памяти V8 глобальных обработчиков.
used_global_handles_size Значение used_global_handles_size — используемый размер памяти V8 глобальных обработчиков.
external_memory Значение external_memory — размер памяти буферов массивов и внешних строк.
{
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
} copy
v8.queryObjects(ctor[, options])
-
ctor<Функция> Конструктор, который можно использовать для поиска по цепочке прототипов, чтобы отфильтровать целевые объекты в куче. -
options<неопределённо> | <Объект>-
format<строка> Если это'count', возвращается количество совпавших объектов. Если это'summary', возвращается массив со строками-резюме совпавших объектов.
-
- Возвращает: {число|Массив<строка>}
Это аналогично queryObjects() API консоли, предоставляемой консолью Chromium DevTools. Его можно использовать для поиска объектов, у которых в цепочке прототипов есть совпадающий конструктор в куче после полного сбора мусора, что может быть полезно для тестирования регрессий утечек памяти. Чтобы избежать неожиданных результатов, пользователи должны избегать использования этого API для конструкторов, реализацию которых они не контролируют, или для конструкторов, которые могут вызываться другими участниками приложения.
Чтобы избежать случайных утечек, этот API не возвращает сырые ссылки на найденные объекты. По умолчанию он возвращает количество найденных объектов. Если options.format равно 'summary', он возвращает массив, содержащий краткие строковые представления каждого объекта. Видимость, предоставляемая в этом API, аналогична той, что предоставляет дамп кучи, при этом пользователи могут сэкономить затраты на сериализацию и разбор и напрямую фильтровать целевые объекты во время поиска.
В результаты включаются только объекты, созданные в текущем контексте выполнения.
Модули CJS
const { queryObjects } = require('node:v8');
class A { foo = 'bar'; }
console.log(queryObjects(A)); // 0
const a = new A();
console.log(queryObjects(A)); // 1
// [ "A { foo: 'bar' }" ]
console.log(queryObjects(A, { format: 'summary' }));
class B extends A { bar = 'qux'; }
const b = new B();
console.log(queryObjects(B)); // 1
// [ "B { foo: 'bar', bar: 'qux' }" ]
console.log(queryObjects(B, { format: 'summary' }));
// Note that, when there are child classes inheriting from a constructor,
// the constructor also shows up in the prototype chain of the child
// classes's prototoype, so the child classes's prototoype would also be
// included in the result.
console.log(queryObjects(A)); // 3
// [ "B { foo: 'bar', bar: 'qux' }", 'A {}', "A { foo: 'bar' }" ]
console.log(queryObjects(A, { format: 'summary' }));
Модули MJS
import { queryObjects } from 'node:v8';
class A { foo = 'bar'; }
console.log(queryObjects(A)); // 0
const a = new A();
console.log(queryObjects(A)); // 1
// [ "A { foo: 'bar' }" ]
console.log(queryObjects(A, { format: 'summary' }));
class B extends A { bar = 'qux'; }
const b = new B();
console.log(queryObjects(B)); // 1
// [ "B { foo: 'bar', bar: 'qux' }" ]
console.log(queryObjects(B, { format: 'summary' }));
// Note that, when there are child classes inheriting from a constructor,
// the constructor also shows up in the prototype chain of the child
// classes's prototoype, so the child classes's prototoype would also be
// included in the result.
console.log(queryObjects(A)); // 3
// [ "B { foo: 'bar', bar: 'qux' }", 'A {}', "A { foo: 'bar' }" ]
console.log(queryObjects(A, { format: 'summary' }));
v8.setFlagsFromString(flags)
-
flags<строка>
Метод v8.setFlagsFromString() может использоваться для программной установки флагов командной строки V8. Этот метод следует использовать с осторожностью. Изменение настроек после запуска виртуальной машины может привести к непредсказуемому поведению, включая сбои и потерю данных; или же это может просто ничего не сделать.
Доступные для версии Node.js параметры V8 можно определить, выполнив node --v8-options.
Использование:
// Print GC events to stdout for one minute.
const v8 = require('node:v8');
v8.setFlagsFromString('--trace_gc');
setTimeout(() => { v8.setFlagsFromString('--notrace_gc'); }, 60e3); copy
v8.stopCoverage()
Метод v8.stopCoverage() позволяет пользователю остановить сбор данных покрытия, начатый NODE_V8_COVERAGE, чтобы V8 мог освободить записи счётчиков выполнения и оптимизировать код. Это можно использовать совместно с v8.takeCoverage(), если пользователь хочет собрать покрытие по требованию.
v8.takeCoverage()
Метод v8.takeCoverage() позволяет пользователю записать данные покрытия, начатые NODE_V8_COVERAGE, на диск по требованию. Этот метод может вызываться несколько раз в течение жизни процесса. Каждый раз счётчики выполнения будут сброшены, и новый отчёт о покрытии будет записан в каталог, указанный в NODE_V8_COVERAGE.
При завершении процесса последний отчёт о покрытии всё равно будет записан на диск, если метод v8.stopCoverage() не вызывается перед завершением процесса.
v8.writeHeapSnapshot([filename[,options]])
-
filename<строка> Путь к файлу, куда должен быть сохранён снимок кучи V8. Если не указан, будет сгенерировано имя файла по шаблону'Heap-${yyyymmdd}-${hhmmss}-${pid}-${thread_id}.heapsnapshot', где{pid}— идентификатор процесса Node.js,{thread_id}—0, когдаwriteHeapSnapshot()вызывается из основного потока Node.js или идентификатор потока работника. -
options<Объект>-
exposeInternals<логическое значение> Если true, раскрыть внутренности в снимке кучи. По умолчанию:false. -
exposeNumericValues<логическое значение> Если true, раскрыть числовые значения в искусственных полях. По умолчанию:false.
-
- Возвращает: <строка> Имя файла, в который был сохранён снимок.
Создаёт снимок текущей кучи V8 и записывает его в файл JSON. Этот файл предназначен для использования с инструментами, такими как Chrome DevTools. Схема JSON не документирована и специфична для движка V8, и может изменяться от одной версии V8 к другой.
Снимок кучи специфичен для отдельной изоляции V8. При использовании потоков работников, снимок кучи, созданный из основного потока, не будет содержать никакой информации о работниках, и наоборот.
Для создания снимка кучи требуется память примерно в два раза больше, чем размер кучи в момент создания снимка. Это несёт риск завершения процесса из-за убийц по нехватке памяти.
Генерация снимка — это синхронная операция, которая блокирует цикл событий на время, зависящее от размера кучи.
const { writeHeapSnapshot } = require('node:v8');
const {
Worker,
isMainThread,
parentPort,
} = require('node:worker_threads');
if (isMainThread) {
const worker = new Worker(__filename);
worker.once('message', (filename) => {
console.log(`worker heapdump: ${filename}`);
// Now get a heapdump for the main thread.
console.log(`main thread heapdump: ${writeHeapSnapshot()}`);
});
// Tell the worker to create a heapdump.
worker.postMessage('heapdump');
} else {
parentPort.once('message', (message) => {
if (message === 'heapdump') {
// Generate a heapdump for the worker
// and return the filename to the parent.
parentPort.postMessage(writeHeapSnapshot());
}
});
} copy
v8.setHeapSnapshotNearHeapLimit(limit)
-
limit<целое число>
API является пустой операцией, если --heapsnapshot-near-heap-limit уже установлено из командной строки или API вызывается более одного раза. limit должно быть положительным целым числом. Дополнительную информацию см. в --heapsnapshot-near-heap-limit.
API сериализации
API сериализации предоставляет средства для сериализации значений JavaScript таким образом, чтобы они были совместимы с алгоритмом структурированного клонирования HTML.
Формат обратной совместимости (т.е. безопасен для хранения на диске). Равные значения JavaScript могут привести к различным результатам сериализации.
v8.serialize(value)
Использует DefaultSerializer для сериализации value в буфер.
ERR_BUFFER_TOO_LARGE будет выброшен при попытке сериализовать огромный объект, который требует буфер большего размера, чем buffer.constants.MAX_LENGTH.
v8.deserialize(buffer)
-
buffer<Буфер> | <Массив типов> | <DataView> Буфер, возвращённый функциейserialize().
Использует DefaultDeserializer с опциями по умолчанию для чтения значения JS из буфера.
Класс: v8.Serializer
new Serializer()
Создаёт новый объект Serializer.
serializer.writeHeader()
Записывает заголовок, который включает версию формата сериализации.
serializer.writeValue(value)
-
value<любое>
Сериализует значение JavaScript и добавляет сериализованное представление в внутренний буфер.
Выбрасывает ошибку, если value нельзя сериализовать.
serializer.releaseBuffer()
- Возвращает: <Буфер>
Возвращает хранимый внутренний буфер. Этот сериализатор не должен использоваться после освобождения буфера. Вызов этого метода приводит к неопределённому поведению, если предыдущий вызов write завершился ошибкой.
serializer.transferArrayBuffer(id, arrayBuffer)
-
id<целое без знака 32 бит> 32-битовое беззнаковое целое число. -
arrayBuffer<ArrayBuffer> ЭкземплярArrayBuffer.
Помечает ArrayBuffer как имеющий содержимое, переданное вне диапазона. Передайте соответствующий ArrayBuffer в контексте десериализации в deserializer.transferArrayBuffer().
serializer.writeUint32(value)
-
value<целое>
Записать 32-битовое беззнаковое целое число. Для использования внутри пользовательского serializer._writeHostObject().
serializer.writeUint64(hi, lo)
Записать 64-битовое беззнаковое целое число, разделённое на 32-битовые части (высокая и низкая). Для использования внутри пользовательского serializer._writeHostObject().
serializer.writeDouble(value)
-
value<число>
Записать значение JS number. Для использования внутри пользовательского serializer._writeHostObject().
serializer.writeRawBytes(buffer)
-
buffer<Буфер> | <Массив типов> | <DataView>
Записать сырые байты во внутренний буфер сериализатора. Десериализатор потребует способ вычисления длины буфера. Для использования внутри пользовательского serializer._writeHostObject().
serializer._writeHostObject(object)
-
object<Объект>
Этот метод вызывается для записи некоторого типа объекта хоста, т.е. объекта, созданного нативными C++ связями. Если сериализация object невозможна, следует выбросить соответствующую ошибку.
Этот метод отсутствует в классе Serializer сам по себе, но может быть предоставлен подклассами.
serializer._getDataCloneError(message)
-
message<строка>
Этот метод вызывается для генерации объектов ошибок, которые будут выброшены, когда объект нельзя клонировать.
Этот метод по умолчанию использует конструктор Error и может быть переопределён в подклассах.
serializer._getSharedArrayBufferId(sharedArrayBuffer)
-
sharedArrayBuffer<SharedArrayBuffer>
Этот метод вызывается, когда сериализатор собирается сериализовать объект SharedArrayBuffer. Он должен вернуть 32-битовое беззнаковое целое число ID для объекта, используя тот же ID, если этот SharedArrayBuffer уже был сериализован. При десериализации этот ID будет передан в deserializer.transferArrayBuffer().
Если объект нельзя сериализовать, следует выбросить исключение.
Этот метод отсутствует в классе Serializer сам по себе, но может быть предоставлен подклассами.
serializer._setTreatArrayBufferViewsAsHostObjects(flag)
-
flag<логическое> По умолчанию:false
Указывает, следует ли рассматривать объекты TypedArray и DataView как объекты хоста, т.е. передавать их в serializer._writeHostObject().
Класс: v8.Deserializer
new Deserializer(buffer)
-
buffer<Буфер> | <Массив типов> | <DataView> Буфер, возвращенный функциейserializer.releaseBuffer().
Создаёт новый объект Deserializer.
deserializer.readHeader()
Читает и проверяет заголовок (включая версию формата). Может, например, отклонить недействительный или неподдерживаемый формат передачи. В этом случае будет выброшено исключение Error.
deserializer.readValue()
Десериализует значение JavaScript из буфера и возвращает его.
deserializer.transferArrayBuffer(id, arrayBuffer)
-
id<целое без знака 32 бит> 32-битовое беззнаковое целое число. -
arrayBuffer<ArrayBuffer> | <SharedArrayBuffer> ЭкземплярArrayBuffer.
Помечает ArrayBuffer как имеющий содержимое, переданное вне диапазона. Передайте соответствующий ArrayBuffer в контексте сериализации в serializer.transferArrayBuffer() (или верните id из serializer._getSharedArrayBufferId() в случае SharedArrayBuffer).
deserializer.getWireFormatVersion()
- Возвращает: <целое>
Считывает версию базового формата передачи. Вероятно, будет полезно для устаревшего кода, читающего старые версии формата передачи. Может не вызываться до .readHeader().
deserializer.readUint32()
- Возвращает: <целое>
Считать 32-битовое беззнаковое целое число и вернуть его. Для использования внутри пользовательского deserializer._readHostObject().
deserializer.readUint64()
- Возвращает: <массив целых>
Считать 64-битовое беззнаковое целое число и вернуть его как массив [hi, lo] с двумя 32-битовыми беззнаковыми целыми числами. Для использования внутри пользовательского deserializer._readHostObject().
deserializer.readDouble()
- Возвращает: <число>
Считывает значение JS number. Для использования внутри пользовательского deserializer._readHostObject().
deserializer.readRawBytes(length)
Считывает сырые байты из внутреннего буфера десериализатора. Параметр length должен соответствовать длине буфера, переданного в serializer.writeRawBytes(). Для использования внутри пользовательского deserializer._readHostObject().
deserializer._readHostObject()
Этот метод используется для чтения какого-либо объекта хоста, т. е. объекта, созданного нативными C++-связями. Если десериализация данных невозможна, должно быть выброшено соответствующее исключение.
Этот метод отсутствует в классе Deserializer сам по себе, но может быть предоставлен подклассами.
Класс: v8.DefaultSerializer
Подкласс Serializer, который сериализует TypedArray (в частности, Buffer) и DataView объекты как объекты хоста и хранит только ту часть их базовых ArrayBuffer , к которым они ссылаются.
Класс: v8.DefaultDeserializer
Подкласс Deserializer, соответствующий формату, записанному в DefaultSerializer.
Обработчики обещаний
Интерфейс promiseHooks может использоваться для отслеживания событий жизненного цикла обещания. Для отслеживания всей асинхронной активности, см. async_hooks, который внутренне использует этот модуль для создания событий жизненного цикла обещаний, в дополнение к событиям других асинхронных ресурсов. Для управления контекстом запроса, см. AsyncLocalStorage.
import { promiseHooks } from 'node:v8';
// There are four lifecycle events produced by promises:
// The `init` event represents the creation of a promise. This could be a
// direct creation such as with `new Promise(...)` or a continuation such
// as `then()` or `catch()`. It also happens whenever an async function is
// called or does an `await`. If a continuation promise is created, the
// `parent` will be the promise it is a continuation from.
function init(promise, parent) {
console.log('a promise was created', { promise, parent });
}
// The `settled` event happens when a promise receives a resolution or
// rejection value. This may happen synchronously such as when using
// `Promise.resolve()` on non-promise input.
function settled(promise) {
console.log('a promise resolved or rejected', { promise });
}
// The `before` event runs immediately before a `then()` or `catch()` handler
// runs or an `await` resumes execution.
function before(promise) {
console.log('a promise is about to call a then handler', { promise });
}
// The `after` event runs immediately after a `then()` handler runs or when
// an `await` begins after resuming from another.
function after(promise) {
console.log('a promise is done calling a then handler', { promise });
}
// Lifecycle hooks may be started and stopped individually
const stopWatchingInits = promiseHooks.onInit(init);
const stopWatchingSettleds = promiseHooks.onSettled(settled);
const stopWatchingBefores = promiseHooks.onBefore(before);
const stopWatchingAfters = promiseHooks.onAfter(after);
// Or they may be started and stopped in groups
const stopHookSet = promiseHooks.createHook({
init,
settled,
before,
after,
});
// To stop a hook, call the function returned at its creation.
stopWatchingInits();
stopWatchingSettleds();
stopWatchingBefores();
stopWatchingAfters();
stopHookSet(); copy
promiseHooks.onInit(init)
-
init<Функция> Обратный вызовinitдля вызова при создании обещания. - Возвращает: <Функция> Вызов для остановки обработчика.
Обработчик init должен быть обычной функцией. Предоставление асинхронной функции приведет к ошибке, так как это создаст бесконечный цикл микрозадач.
Модули MJS
import { promiseHooks } from 'node:v8';
const stop = promiseHooks.onInit((promise, parent) => {});
Модули CJS
const { promiseHooks } = require('node:v8');
const stop = promiseHooks.onInit((promise, parent) => {});
promiseHooks.onSettled(settled)
-
settled<Функция> Обратный вызовsettledдля вызова при разрешении или отклонении обещания. - Возвращает: <Функция> Вызов для остановки обработчика.
Обработчик settled должен быть обычной функцией. Предоставление асинхронной функции приведет к ошибке, так как это создаст бесконечный цикл микрозадач.
Модули MJS
import { promiseHooks } from 'node:v8';
const stop = promiseHooks.onSettled((promise) => {});
Модули CJS
const { promiseHooks } = require('node:v8');
const stop = promiseHooks.onSettled((promise) => {});
promiseHooks.onBefore(before)
-
before<Функция> Обратный вызовbeforeдля вызова перед выполнением продолжения обещания. - Возвращает: <Функция> Вызов для остановки обработчика.
Обработчик before должен быть обычной функцией. Предоставление асинхронной функции приведет к ошибке, так как это создаст бесконечный цикл микрозадач.
Модули MJS
import { promiseHooks } from 'node:v8';
const stop = promiseHooks.onBefore((promise) => {});
Модули CJS
const { promiseHooks } = require('node:v8');
const stop = promiseHooks.onBefore((promise) => {});
promiseHooks.onAfter(after)
-
after<Функция> Обратный вызовafterдля вызова после выполнения продолжения обещания. - Возвращает: <Функция> Вызов для остановки обработчика.
Обработчик after должен быть обычной функцией. Предоставление асинхронной функции приведет к ошибке, так как это создаст бесконечный цикл микрозадач.
Модули MJS
import { promiseHooks } from 'node:v8';
const stop = promiseHooks.onAfter((promise) => {});
Модули CJS
const { promiseHooks } = require('node:v8');
const stop = promiseHooks.onAfter((promise) => {});
promiseHooks.createHook(callbacks)
-
callbacks<Объект> Обратные вызовы Обработчики для регистрации - Возвращает: <Функция> Используется для отключения обработчиков
Обратные вызовы обработчика должны быть обычными функциями. Предоставление асинхронных функций приведет к ошибке, так как это создаст бесконечный цикл микрозадач.
Регистрирует функции, которые будут вызываться для различных событий жизненного цикла каждого обещания.
Обратные вызовы init()/before()/after()/settled() вызываются для соответствующих событий в течение жизненного цикла обещания.
Все обратные вызовы необязательны. Например, если нужно отслеживать только создание обещания, то нужно передать только обратный вызов init. Подробности всех функций, которые можно передать в callbacks, находятся в разделе Обратные вызовы обработчиков.
Модули MJS
import { promiseHooks } from 'node:v8';
const stopAll = promiseHooks.createHook({
init(promise, parent) {},
});
Модули CJS
const { promiseHooks } = require('node:v8');
const stopAll = promiseHooks.createHook({
init(promise, parent) {},
}); Обратные вызовы обработчиков
Ключевые события в жизни обещания были разделены на четыре области: создание обещания, до/после вызова обработчика продолжения или вокруг ожидания, и при разрешении или отклонении обещания.
Хотя эти обработчики похожи на обработчики async_hooks, у них нет обработчика destroy. Другие типы асинхронных ресурсов обычно представляют сокеты или дескрипторы файлов, которые имеют отдельное состояние "закрыто" для выражения события жизненного цикла destroy, в то время как обещания остаются пригодными для использования, пока к ним может получить доступ код. Для отслеживания обещаний используется отслеживание сборки мусора, чтобы они соответствовали модели событий async_hooks, однако это отслеживание очень дорогостоящее, и они могут не быть удалены из памяти.
Поскольку обещания являются асинхронными ресурсами, жизненный цикл которых отслеживается с помощью механизма обработчиков обещаний, обратные вызовы init(), before(), after(), и settled() не должны быть асинхронными функциями, так как они создают больше обещаний, что приведет к бесконечному циклу.
Хотя этот API используется для подачи событий обещаний в async_hooks, порядок между ними не определен. Оба API являются многопользовательскими и, следовательно, могут генерировать события в любом порядке относительно друг друга.
init(promise, parent)
-
promise<Обещание> Создаваемое обещание. -
parent<Обещание> Продолжение обещания, если применимо.
Вызывается при создании обещания. Это не означает, что соответствующие события before/after будут происходить, только то, что такая возможность существует. Это произойдет, если обещание будет создано без продолжения.
before(promise)
-
promise<Обещание>
Вызывается перед выполнением продолжения обещания. Это может быть в форме обработчиков then(), catch(), или finally() или возобновления await.
Обратный вызов before будет вызван 0 до N раз. Обратный вызов before обычно вызывается 0 раз, если для обещания никогда не было создано продолжение. Обратный вызов before может быть вызван много раз в случае, если от одного и того же обещания были созданы многочисленные продолжения.
after(promise)
-
promise<Обещание>
Вызывается сразу после выполнения продолжения обещания. Это может быть после обработчика then(), catch(), или finally() или перед await после другого await.
settled(promise)
-
promise<Обещание>
Вызывается при получении обещанием значения разрешения или отклонения. Это может произойти синхронно в случае Promise.resolve() или Promise.reject().
API моментальных снимков запуска
Интерфейс v8.startupSnapshot может использоваться для добавления обработчиков сериализации и десериализации для пользовательских моментальных снимков запуска.
$ node --snapshot-blob snapshot.blob --build-snapshot entry.js # This launches a process with the snapshot $ node --snapshot-blob snapshot.blob copy
В примере выше, entry.js может использовать методы интерфейса v8.startupSnapshot для указания способа сохранения информации о пользовательских объектах в моментальном снимке во время сериализации и того, как эта информация может быть использована для синхронизации этих объектов во время десериализации снимка. Например, если entry.js содержит следующий скрипт:
'use strict';
const fs = require('node:fs');
const zlib = require('node:zlib');
const path = require('node:path');
const assert = require('node:assert');
const v8 = require('node:v8');
class BookShelf {
storage = new Map();
// Reading a series of files from directory and store them into storage.
constructor(directory, books) {
for (const book of books) {
this.storage.set(book, fs.readFileSync(path.join(directory, book)));
}
}
static compressAll(shelf) {
for (const [ book, content ] of shelf.storage) {
shelf.storage.set(book, zlib.gzipSync(content));
}
}
static decompressAll(shelf) {
for (const [ book, content ] of shelf.storage) {
shelf.storage.set(book, zlib.gunzipSync(content));
}
}
}
// __dirname here is where the snapshot script is placed
// during snapshot building time.
const shelf = new BookShelf(__dirname, [
'book1.en_US.txt',
'book1.es_ES.txt',
'book2.zh_CN.txt',
]);
assert(v8.startupSnapshot.isBuildingSnapshot());
// On snapshot serialization, compress the books to reduce size.
v8.startupSnapshot.addSerializeCallback(BookShelf.compressAll, shelf);
// On snapshot deserialization, decompress the books.
v8.startupSnapshot.addDeserializeCallback(BookShelf.decompressAll, shelf);
v8.startupSnapshot.setDeserializeMainFunction((shelf) => {
// process.env and process.argv are refreshed during snapshot
// deserialization.
const lang = process.env.BOOK_LANG || 'en_US';
const book = process.argv[1];
const name = `${book}.${lang}.txt`;
console.log(shelf.storage.get(name));
}, shelf); copy Результат работы будет выводить данные, десериализованные из моментального снимка во время запуска, используя обновлённые process.env и process.argv запущенного процесса:
$ BOOK_LANG=es_ES node --snapshot-blob snapshot.blob book1 # Prints content of book1.es_ES.txt deserialized from the snapshot. copy
В настоящее время приложение, десериализованное из снимка пользовательского пространства, не может быть снова сфотографировано, поэтому эти API доступны только приложениям, которые не десериализованы из снимка пользовательского пространства.
v8.startupSnapshot.addSerializeCallback(callback[, data])
-
callback<Функция> Обработчик, вызываемый перед сериализацией. -
data<любой> Необязательные данные, которые будут переданы обработчикуcallbackпри его вызове.
Добавляет обработчик, который будет вызван, когда экземпляр Node.js собирается сериализоваться в моментальный снимок и завершиться. Это может быть использовано для освобождения ресурсов, которые не должны или не могут быть сериализованы, или для преобразования пользовательских данных в форму, более подходящую для сериализации.
Обработчики выполняются в порядке их добавления.
v8.startupSnapshot.addDeserializeCallback(callback[, data])
-
callback<Функция> Обработчик, вызываемый после десериализации моментального снимка. -
data<любой> Необязательные данные, которые будут переданы обработчикуcallbackпри его вызове.
Добавляет обработчик, который будет вызван при десериализации экземпляра Node.js из моментального снимка. callback и data (если указаны) будут сериализованы в моментальный снимок; их можно использовать для повторной инициализации состояния приложения или для повторного получения ресурсов, необходимых приложении, когда приложение перезапускается из моментального снимка.
Обработчики выполняются в порядке их добавления.
v8.startupSnapshot.setDeserializeMainFunction(callback[, data])
-
callback<Функция> Обработчик, вызываемый в качестве точки входа после десериализации моментального снимка. -
data<любой> Необязательные данные, которые будут переданы обработчикуcallbackпри его вызове.
Устанавливает точку входа приложения Node.js при его десериализации из моментального снимка. Этот метод может быть вызван только один раз в скрипте создания снимка. Если он вызван, десериализованному приложению больше не нужен дополнительный скрипт точки входа для запуска, и оно просто вызовет обработчик вместе с десериализованными данными (если предоставлены); в противном случае десериализованному приложению всё равно требуется скрипт точки входа.
v8.startupSnapshot.isBuildingSnapshot()
- Возвращает: <логическое значение>
Возвращает true, если экземпляр Node.js запускается для создания моментального снимка.
Класс: v8.GCProfiler
Этот API собирает данные GC в текущей нити.
new v8.GCProfiler()
Создаёт новый экземпляр класса v8.GCProfiler.
profiler.start()
Начинает сбор данных GC.
profiler.stop()
Останавливает сбор данных GC и возвращает объект. Содержание объекта:
{
"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
} copy Вот пример.
const { GCProfiler } = require('v8');
const profiler = new GCProfiler();
profiler.start();
setTimeout(() => {
console.log(profiler.stop());
}, 1000); copy
© Joyent, Inc. and other Node contributors
Licensed under the MIT License.
Node.js is a trademark of Joyent, Inc. and is used with its permission.
We are not endorsed by or affiliated with Joyent.
https://nodejs.org/api/v8.html