V8
Исходный код: lib/v8.js
Модуль node:v8 предоставляет API, специфичные для версии V8, встроенной в бинарный файл Node.js. Доступ к нему можно получить с помощью:
const v8 = require('node:v8'); copy
v8.cachedDataVersionTag()
- Возвращает: <integer>
Возвращает целое число — тег версии, полученный на основе версии 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()
- Возвращает: <Object>
Получает статистику о коде и его метаданных в куче; см. API V8 GetHeapCodeAndMetadataStatistics. Возвращает объект со следующими свойствами:
-
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,
} copy
v8.getHeapSnapshot([options])
-
options<Object> -
Возвращает: <stream.Readable> Поток Readable, содержащий снимок кучи V8.
Создаёт снимок текущей кучи V8 и возвращает поток Readable, который можно использовать для чтения сериализованного представления в формате JSON. Этот формат потока JSON предназначен для использования с такими инструментами, как Chrome DevTools. Схема JSON не документирована и специфична для движка V8. Поэтому она может меняться от одной версии V8 к другой.
Для создания снимка кучи требуется память объёмом примерно в два раза больше размера кучи на момент создания снимка. Это создаёт риск завершения процесса средствами OOM killer.
Создание снимка — синхронная операция, которая блокирует цикл событий на время, зависящее от размера кучи.
// Print heap snapshot to the console
const v8 = require('node:v8');
const stream = v8.getHeapSnapshot();
stream.pipe(process.stdout); copy
v8.getHeapSpaceStatistics()
- Возвращает: <Object[]>
Возвращает статистику по пространствам кучи V8, то есть сегментам, из которых состоит куча V8. Ни порядок пространств кучи, ни наличие того или иного пространства не гарантируются, поскольку статистика предоставляется функцией V8 GetHeapSpaceStatistics и может меняться от одной версии V8 к другой.
Возвращаемое значение представляет собой массив объектов со следующими свойствами:
-
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
}
] copy
v8.getHeapStatistics()
- Возвращает: <Object>
Возвращает объект со следующими свойствами:
-
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 Значение total_heap_size — это количество байтов, выделенных V8 для кучи. Оно может увеличиваться, если для used_heap требуется больше памяти.
total_heap_size_executable Значение total_heap_size_executable — это размер области кучи в байтах, в которой может содержаться исполняемый код. Сюда входит память, используемая кодом, скомпилированным JIT-компилятором, и любая память, которая должна оставаться исполняемой.
total_physical_size Значение total_physical_size — это фактический объём физической памяти, используемой кучей V8, в байтах. Это объём выделенной (или используемой), а не зарезервированной памяти.
total_available_size Значение total_available_size — это количество байтов памяти, доступной куче V8. Это значение показывает, сколько дополнительной памяти может использовать V8 до достижения ограничения размера кучи.
used_heap_size Значение used_heap_size — это количество байтов, которое в данный момент занимают объекты JavaScript V8. Это фактически используемая память; в неё не входит выделенная, но ещё не использованная память.
heap_size_limit Значение heap_size_limit — это максимальный размер кучи V8 в байтах (ограничение по умолчанию, определяемое системными ресурсами, или значение, переданное параметру --max_old_space_size).
malloced_memory Значение malloced_memory — это количество байтов, выделенных V8 с помощью malloc.
peak_malloced_memory Значение peak_malloced_memory — это максимальное количество байтов, выделенных V8 с помощью malloc за время существования процесса.
does_zap_garbage — это логическое значение 0/1, указывающее, включён ли параметр --zap_code_space. При его включении V8 перезаписывает мусор в куче битовым шаблоном. Объём памяти RSS (размер резидентного набора) увеличивается, поскольку постоянно затрагиваются все страницы кучи, из-за чего операционной системе становится сложнее выгрузить их в файл подкачки.
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.getCppHeapStatistics([detailLevel])
Получает статистику CppHeap о потреблении и использовании памяти с помощью функции V8 CollectStatistics(), которая может меняться от одной версии V8 к другой.
-
detailLevel<string> | <undefined>: По умолчанию:'detailed'. Задаёт степень детализации возвращаемой статистики. Допустимые значения:-
'brief': краткая статистика содержит только сводные данные о выделенной и используемой памяти для всей кучи. -
'detailed': подробная статистика также содержит разбивку по пространствам и страницам, а также статистику списков свободных блоков и гистограммы типов объектов.
-
Метод возвращает объект со структурой, аналогичной объекту cppgc::HeapStatistics. Дополнительные сведения о свойствах объекта см. в документации V8.
// Detailed
({
committed_size_bytes: 131072,
resident_size_bytes: 131072,
used_size_bytes: 152,
space_statistics: [
{
name: 'NormalPageSpace0',
committed_size_bytes: 0,
resident_size_bytes: 0,
used_size_bytes: 0,
page_stats: [{}],
free_list_stats: {},
},
{
name: 'NormalPageSpace1',
committed_size_bytes: 131072,
resident_size_bytes: 131072,
used_size_bytes: 152,
page_stats: [{}],
free_list_stats: {},
},
{
name: 'NormalPageSpace2',
committed_size_bytes: 0,
resident_size_bytes: 0,
used_size_bytes: 0,
page_stats: [{}],
free_list_stats: {},
},
{
name: 'NormalPageSpace3',
committed_size_bytes: 0,
resident_size_bytes: 0,
used_size_bytes: 0,
page_stats: [{}],
free_list_stats: {},
},
{
name: 'LargePageSpace',
committed_size_bytes: 0,
resident_size_bytes: 0,
used_size_bytes: 0,
page_stats: [{}],
free_list_stats: {},
},
],
type_names: [],
detail_level: 'detailed',
}); copy // Brief
({
committed_size_bytes: 131072,
resident_size_bytes: 131072,
used_size_bytes: 128864,
space_statistics: [],
type_names: [],
detail_level: 'brief',
}); copy
v8.queryObjects(ctor[, options])
-
ctor<Function> Конструктор, который можно использовать для поиска по цепочке прототипов, чтобы отфильтровать целевые объекты в куче. -
options<undefined> | <Object>-
format<string> Если это'count', возвращается количество найденных объектов. Если это'summary', возвращается массив строк со сводными описаниями найденных объектов.
-
- Возвращает: {number|Array
}
Этот метод похож на API консоли queryObjects(), предоставляемый консолью Chromium DevTools. Он позволяет после полной сборки мусора искать в куче объекты, у которых в цепочке прототипов есть соответствующий конструктор. Это может быть полезно для регрессионных тестов на утечки памяти. Во избежание неожиданных результатов не следует использовать этот API для конструкторов, реализацию которых пользователь не контролирует, или конструкторов, которые могут вызываться другими участниками приложения.
Чтобы избежать случайных утечек, этот API не возвращает прямые ссылки на найденные объекты. По умолчанию он возвращает количество найденных объектов. Если options.format имеет значение 'summary', он возвращает массив с краткими строковыми представлениями каждого объекта. Доступ к данным, предоставляемый этим API, аналогичен доступу к данным снимка кучи; при этом можно избежать затрат на сериализацию и разбор данных и сразу фильтровать целевые объекты во время поиска.
В результаты включаются только объекты, созданные в текущем контексте выполнения.
CommonJS
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 prototype, so the child classes's prototype 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' }));Модули JavaScript
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 prototype, so the child classes's prototype 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<string>
Метод v8.setFlagsFromString() позволяет программно задавать флаги командной строки V8. Использовать этот метод следует с осторожностью. Изменение параметров после запуска виртуальной машины может привести к непредсказуемому поведению, включая сбои и потерю данных, или же не дать никакого результата.
Список параметров V8, доступных для версии Node.js, можно получить, выполнив 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<string> Путь к файлу, в который нужно сохранить снимок кучи V8. Если он не указан, будет создано имя файла по шаблону'Heap-${yyyymmdd}-${hhmmss}-${pid}-${thread_id}.heapsnapshot', где{pid}— PID процесса Node.js, а{thread_id}будет равно0, еслиwriteHeapSnapshot()вызывается из основного потока Node.js, или идентификатору рабочего потока. -
options<Object> - Возвращает: <string> Имя файла, в который был сохранён снимок.
Создаёт снимок текущей кучи V8 и записывает его в файл JSON. Этот файл предназначен для использования с такими инструментами, как Chrome DevTools. Схема JSON не документирована и специфична для движка V8, поэтому может меняться от одной версии V8 к другой.
Снимок кучи относится к одному изоляту V8. При использовании рабочих потоков снимок кучи, созданный в основном потоке, не будет содержать сведений о рабочих потоках, и наоборот.
Для создания снимка кучи требуется память объёмом примерно в два раза больше размера кучи на момент создания снимка. Это создаёт риск завершения процесса средствами OOM killer.
Создание снимка — синхронная операция, которая блокирует цикл событий на время, зависящее от размера кучи.
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<integer>
API ничего не делает, если --heapsnapshot-near-heap-limit уже задан в командной строке или если API вызывается более одного раза. Значение limit должно быть положительным целым числом. Дополнительные сведения см. в разделе --heapsnapshot-near-heap-limit.
API сериализации
API сериализации предоставляет средства для сериализации значений JavaScript способом, совместимым с алгоритмом структурированного клонирования HTML.
Формат обратно совместим (то есть его безопасно хранить на диске). Результатом сериализации равных значений JavaScript могут быть разные данные.
v8.serialize(value)
Использует DefaultSerializer для сериализации value в буфер.
При попытке сериализовать огромный объект, для которого требуется буфер размером больше buffer.constants.MAX_LENGTH, будет выброшено исключение ERR_BUFFER_TOO_LARGE.
v8.deserialize(buffer)
-
buffer<Buffer> | <TypedArray> | <DataView> Буфер, возвращённыйserialize().
Использует DefaultDeserializer с параметрами по умолчанию для чтения значения JS из буфера.
Класс: v8.Serializer
new Serializer()
Создаёт новый объект Serializer.
serializer.writeHeader()
Записывает заголовок, содержащий версию формата сериализации.
serializer.writeValue(value)
-
value<any>
Сериализует значение JavaScript и добавляет его сериализованное представление во внутренний буфер.
Если value не удаётся сериализовать, будет выброшена ошибка.
serializer.releaseBuffer()
- Возвращает: <Buffer>
Возвращает сохранённый внутренний буфер. После освобождения буфера этот сериализатор использовать нельзя. Вызов этого метода приводит к неопределённому поведению, если предыдущая запись завершилась ошибкой.
serializer.transferArrayBuffer(id, arrayBuffer)
-
id<integer> Беззнаковое 32-битное целое число. -
arrayBuffer<ArrayBuffer> ЭкземплярArrayBuffer.
Отмечает ArrayBuffer как объект, содержимое которого передаётся вне основного потока данных. Передайте соответствующий ArrayBuffer в контексте десериализации в deserializer.transferArrayBuffer().
serializer.writeUint32(value)
-
value<integer>
Записывает необработанное беззнаковое 32-битное целое число. Используется внутри пользовательского serializer._writeHostObject().
serializer.writeUint64(hi, lo)
Записывает необработанное беззнаковое 64-битное целое число, разделённое на старшую и младшую 32-битные части. Используется внутри пользовательского serializer._writeHostObject().
serializer.writeDouble(value)
-
value<number>
Записывает значение number JS. Используется внутри пользовательского serializer._writeHostObject().
serializer.writeRawBytes(buffer)
-
buffer<Buffer> | <TypedArray> | <DataView>
Записывает необработанные байты во внутренний буфер сериализатора. Десериализатору потребуется способ вычислить длину буфера. Используется внутри пользовательского serializer._writeHostObject().
serializer._writeHostObject(object)
-
object<Object>
Этот метод вызывается для записи объектов хоста — то есть объектов, созданных нативными привязками C++. Если сериализовать object невозможно, следует выбросить подходящее исключение.
Этот метод отсутствует в самом классе Serializer, но может быть предоставлен подклассами.
serializer._getDataCloneError(message)
-
message<string>
Этот метод вызывается для создания объектов ошибок, которые будут выброшены, если объект невозможно клонировать.
По умолчанию этот метод использует конструктор Error; его можно переопределить в подклассах.
serializer._getSharedArrayBufferId(sharedArrayBuffer)
-
sharedArrayBuffer<SharedArrayBuffer>
Этот метод вызывается, когда сериализатор собирается сериализовать объект SharedArrayBuffer. Он должен возвращать беззнаковый 32-битный идентификатор объекта, используя тот же идентификатор, если этот SharedArrayBuffer уже был сериализован. При десериализации этот идентификатор будет передан в deserializer.transferArrayBuffer().
Если объект невозможно сериализовать, следует выбросить исключение.
Этот метод отсутствует в самом классе Serializer, но может быть предоставлен подклассами.
serializer._setTreatArrayBufferViewsAsHostObjects(flag)
-
flag<boolean> По умолчанию:false
Указывает, следует ли считать объекты TypedArray и DataView объектами хоста, то есть передавать их в serializer._writeHostObject().
Класс: v8.Deserializer
new Deserializer(buffer)
-
buffer<Buffer> | <TypedArray> | <DataView> Буфер, возвращённый методомserializer.releaseBuffer().
Создаёт новый объект Deserializer.
deserializer.readHeader()
Читает и проверяет заголовок (включая версию формата). Например, может отклонить недопустимый или неподдерживаемый формат передачи данных. В этом случае выбрасывается Error.
deserializer.readValue()
Десериализует значение JavaScript из буфера и возвращает его.
deserializer.transferArrayBuffer(id, arrayBuffer)
-
id<integer> Беззнаковое 32-битное целое число. -
arrayBuffer<ArrayBuffer> | <SharedArrayBuffer> ЭкземплярArrayBuffer.
Отмечает ArrayBuffer как объект, содержимое которого передаётся вне основного потока данных. Передайте соответствующий ArrayBuffer в контексте сериализации в serializer.transferArrayBuffer() (или верните id из serializer._getSharedArrayBufferId() в случае объектов SharedArrayBuffers).
deserializer.getWireFormatVersion()
- Возвращает: <integer>
Читает версию используемого формата передачи данных. Вероятно, это будет полезно главным образом устаревшему коду, читающему старые версии формата. Нельзя вызывать до .readHeader().
deserializer.readUint32()
- Возвращает: <integer>
Читает необработанное беззнаковое 32-битное целое число и возвращает его. Используется внутри пользовательского deserializer._readHostObject().
deserializer.readUint64()
- Возвращает: <integer[]>
Читает необработанное беззнаковое 64-битное целое число и возвращает его в виде массива [hi, lo] с двумя элементами — беззнаковыми 32-битными целыми числами. Используется внутри пользовательского deserializer._readHostObject().
deserializer.readDouble()
- Возвращает: <number>
Читает значение number JS. Используется внутри пользовательского deserializer._readHostObject().
deserializer.readRawBytes(length)
Читает необработанные байты из внутреннего буфера десериализатора. Параметр length должен соответствовать длине буфера, переданного в serializer.writeRawBytes(). Используется внутри пользовательского deserializer._readHostObject().
deserializer._readHostObject()
Этот метод вызывается для чтения объектов хоста — то есть объектов, созданных нативными привязками C++. Если десериализовать данные невозможно, следует выбросить подходящее исключение.
Этот метод отсутствует в самом классе Deserializer, но может быть предоставлен подклассами.
Класс: v8.DefaultSerializer
Подкласс Serializer, который сериализует TypedArray (в частности, Buffer) и объекты DataView как объекты хоста и сохраняет только ту часть лежащих в их основе ArrayBuffers, на которую они ссылаются.
Класс: 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<Function> Функция обратного вызоваinit, вызываемая при создании промиса. - Возвращает: <Function> Функция для остановки хука.
Хук init должен быть обычной функцией. Передача асинхронной функции приведёт к ошибке, поскольку она создаст бесконечный цикл микрозадач.
Модули JavaScript
import { promiseHooks } from 'node:v8';
const stop = promiseHooks.onInit((promise, parent) => {});CommonJS
const { promiseHooks } = require('node:v8');
const stop = promiseHooks.onInit((promise, parent) => {});
promiseHooks.onSettled(settled)
-
settled<Function> Функция обратного вызоваsettled, вызываемая при выполнении или отклонении промиса. - Возвращает: <Function> Функция для остановки хука.
Хук settled должен быть обычной функцией. Передача асинхронной функции приведёт к ошибке, поскольку она создаст бесконечный цикл микрозадач.
Модули JavaScript
import { promiseHooks } from 'node:v8';
const stop = promiseHooks.onSettled((promise) => {});CommonJS
const { promiseHooks } = require('node:v8');
const stop = promiseHooks.onSettled((promise) => {});
promiseHooks.onBefore(before)
-
before<Function> Функция обратного вызоваbefore, вызываемая перед выполнением продолжения промиса. - Возвращает: <Function> Функция для остановки хука.
Хук before должен быть обычной функцией. Передача асинхронной функции приведёт к ошибке, поскольку она создаст бесконечный цикл микрозадач.
Модули JavaScript
import { promiseHooks } from 'node:v8';
const stop = promiseHooks.onBefore((promise) => {});CommonJS
const { promiseHooks } = require('node:v8');
const stop = promiseHooks.onBefore((promise) => {});
promiseHooks.onAfter(after)
-
after<Function> Функция обратного вызоваafter, вызываемая после выполнения продолжения промиса. - Возвращает: <Function> Функция для остановки хука.
Хук after должен быть обычной функцией. Передача асинхронной функции приведёт к ошибке, поскольку она создаст бесконечный цикл микрозадач.
Модули JavaScript
import { promiseHooks } from 'node:v8';
const stop = promiseHooks.onAfter((promise) => {});CommonJS
const { promiseHooks } = require('node:v8');
const stop = promiseHooks.onAfter((promise) => {});
promiseHooks.createHook(callbacks)
-
callbacks<Object> Коллбэки хуков (Hook Callbacks) для регистрации-
init<Function> Функция обратного вызоваinit. -
before<Function> Функция обратного вызоваbefore. -
after<Function> Функция обратного вызоваafter. -
settled<Function> Функция обратного вызоваsettled.
-
- Возвращает: <Function> Используется для отключения хуков
Коллбэки хуков должны быть обычными функциями. Передача асинхронных функций приведёт к ошибке, поскольку они создадут бесконечный цикл микрозадач.
Регистрирует функции, вызываемые при различных событиях жизненного цикла каждого промиса.
Коллбэки init()/before()/after()/settled() вызываются при соответствующих событиях в течение жизненного цикла промиса.
Все коллбэки необязательны. Например, если нужно отслеживать только создание промисов, достаточно передать коллбэк init. Описание всех функций, которые можно передать в callbacks, приведено в разделе Коллбэки хуков.
Модули JavaScript
import { promiseHooks } from 'node:v8';
const stopAll = promiseHooks.createHook({
init(promise, parent) {},
});CommonJS
const { promiseHooks } = require('node:v8');
const stopAll = promiseHooks.createHook({
init(promise, parent) {},
});Коллбэки хуков
Ключевые события жизненного цикла промиса разделены на четыре категории: создание промиса, выполнение обработчика продолжения или его начало и завершение вокруг await, а также выполнение или отклонение промиса.
Хотя эти хуки похожи на хуки async_hooks, в них отсутствует хук destroy. Другие типы асинхронных ресурсов обычно представляют сокеты или файловые дескрипторы, у которых есть отдельное состояние «закрыт», обозначающее событие жизненного цикла destroy; промисы же остаются пригодными к использованию, пока код может на них ссылаться. Для включения промисов в модель событий async_hooks используется отслеживание сборки мусора. Однако это отслеживание обходится очень дорого, и сборка мусора может вообще не произойти.
Поскольку промисы — это асинхронные ресурсы, жизненный цикл которых отслеживается механизмом хуков промисов, коллбэки init(), before(), after() и settled() не должны быть асинхронными функциями, так как они создают новые промисы, что привело бы к бесконечному циклу.
Хотя этот API используется для передачи событий промисов в async_hooks, порядок их вызова относительно друг друга не определён. Оба API являются многопользовательскими, поэтому события одного API могут возникать в любом порядке относительно событий другого.
init(promise, parent)
-
promise<Promise> Создаваемый промис. -
parent<Promise> Промис, от которого продолжается цепочка, если он есть.
Вызывается при создании промиса. Это не означает, что произойдут соответствующие события before/after, а лишь указывает на такую возможность. Это произойдёт, если промис создан, но для него так и не создано продолжение.
before(promise)
-
promise<Promise>
Вызывается перед выполнением продолжения промиса. Это может быть обработчик then(), catch() или finally(), а также возобновление выполнения await.
Коллбэк before будет вызван от 0 до N раз. Коллбэк before обычно не вызывается, если для промиса не было создано продолжение. Коллбэк before может вызываться много раз, если для одного промиса создано много продолжений.
after(promise)
-
promise<Promise>
Вызывается сразу после выполнения продолжения промиса. Это может произойти после обработчика then(), catch() или finally() либо перед await после другого await.
settled(promise)
-
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<Function> Функция обратного вызова, вызываемая перед сериализацией. -
data<any> Необязательные данные, передаваемые вcallbackпри вызове.
Добавляет функцию обратного вызова, которая будет вызвана перед сериализацией экземпляра Node.js в снимок и завершением работы. Её можно использовать для освобождения ресурсов, которые не следует или невозможно сериализовать, либо для преобразования пользовательских данных в форму, более подходящую для сериализации.
Функции обратного вызова выполняются в порядке добавления.
v8.startupSnapshot.addDeserializeCallback(callback[, data])
-
callback<Function> Функция обратного вызова, вызываемая после десериализации снимка. -
data<any> Необязательные данные, передаваемые вcallbackпри вызове.
Добавляет функцию обратного вызова, которая будет вызвана при десериализации экземпляра Node.js из снимка. callback и data (если указаны) будут сериализованы в снимок; их можно использовать для повторной инициализации состояния приложения или повторного получения ресурсов, необходимых приложению после его перезапуска из снимка.
Функции обратного вызова выполняются в порядке добавления.
v8.startupSnapshot.setDeserializeMainFunction(callback[, data])
-
callback<Function> Функция обратного вызова, вызываемая в качестве точки входа после десериализации снимка. -
data<any> Необязательные данные, передаваемые вcallbackпри вызове.
Задаёт точку входа приложения Node.js при его десериализации из снимка. Этот метод можно вызвать в скрипте создания снимка только один раз. Если он вызван, десериализованному приложению больше не требуется дополнительный скрипт точки входа для запуска: будет вызван коллбэк с десериализованными данными (если они были указаны). В противном случае для запуска десериализованного приложения по-прежнему потребуется скрипт точки входа.
v8.startupSnapshot.isBuildingSnapshot()
- Возвращает: <boolean>
Возвращает true, если экземпляр Node.js запущен для создания снимка.
Класс: v8.GCProfiler
Этот API собирает данные о сборке мусора в текущем потоке.
new v8.GCProfiler()
Создаёт новый экземпляр класса v8.GCProfiler.
profiler.start()
Начинает сбор данных о сборке мусора.
profiler.stop()
Останавливает сбор данных о сборке мусора и возвращает объект. Содержимое объекта выглядит следующим образом.
{
"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('node:v8');
const profiler = new GCProfiler();
profiler.start();
setTimeout(() => {
console.log(profiler.stop());
}, 1000); copy
v8.isStringOneByteRepresentation(content)
V8 поддерживает только Latin-1/ISO-8859-1 и UTF16 в качестве внутреннего представления строки. Если content использует Latin-1/ISO-8859-1 в качестве внутреннего представления, эта функция вернёт true; в противном случае она вернёт false.
Если этот метод возвращает false, это не означает, что строка содержит символы, отсутствующие в Latin-1/ISO-8859-1. Иногда строка Latin-1 также может быть представлена как UTF16.
const { isStringOneByteRepresentation } = require('node:v8');
const Encoding = {
latin1: 1,
utf16le: 2,
};
const buffer = Buffer.alloc(100);
function writeString(input) {
if (isStringOneByteRepresentation(input)) {
buffer.writeUint8(Encoding.latin1);
buffer.writeUint32LE(input.length, 1);
buffer.write(input, 5, 'latin1');
} else {
buffer.writeUint8(Encoding.utf16le);
buffer.writeUint32LE(input.length * 2, 1);
buffer.write(input, 5, 'utf16le');
}
}
writeString('hello');
writeString('你好'); 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/dist/latest-v22.x/docs/api/v8.html