V8
Исходный код: lib/v8.js
Модуль node:v8
предоставляет API, специфичные для версии V8, встроенной в бинарный файл Node.js. Доступ к нему можно получить с помощью:
const v8 = require('node:v8')
v8.cachedDataVersionTag()
Добавлено в: v8.0.0
- Возвращает: <целое число>
Возвращает целое число, представляющее тег версии, полученный из версии V8, флагов командной строки и обнаруженных возможностей ЦП. Это полезно для определения того, совместим ли буфер cachedData
vm.Script
с этим экземпляром V8.
console.log(v8.cachedDataVersionTag()) // 3947234607
// Значение, возвращаемое v8.cachedDataVersionTag(), получено из версии V8,
// флагов командной строки и обнаруженных возможностей ЦП. Проверьте, что значение
// действительно обновляется при переключении флагов.
v8.setFlagsFromString('--allow_natives_syntax')
console.log(v8.cachedDataVersionTag()) // 183726201
v8.getHeapCodeStatistics()
Добавлено в: v12.8.0
- Возвращает: <Объект>
Получает статистику о коде и его метаданных в куче, см. 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,
}
v8.getHeapSnapshot([options])
[История]
Версия | Изменения |
---|---|
v19.1.0 | Добавлена поддержка параметров для настройки снимка кучи. |
v11.13.0 | Добавлено в: v11.13.0 |
options
<Object>Возвращает: <stream.Readable>
Readable
поток, содержащий снимок кучи V8.
Создает снимок текущей кучи V8 и возвращает поток Readable Stream
, который может использоваться для чтения сериализованного JSON представления. Этот формат JSON потока предназначен для использования с такими инструментами, как Chrome DevTools. Схема JSON не документирована и специфична для движка V8. Поэтому схема может изменяться от одной версии V8 к другой.
Для создания снимка кучи требуется память примерно вдвое большего размера, чем куча в момент создания снимка. Это приводит к риску завершения процесса средствами операционной системы из-за нехватки памяти.
Генерация снимка — это синхронная операция, которая блокирует цикл обработки событий на время, зависящее от размера кучи.
// Вывод снимка кучи в консоль
const v8 = require('node:v8')
const stream = v8.getHeapSnapshot()
stream.pipe(process.stdout)
v8.getHeapSpaceStatistics()
[История]
Версия | Изменения |
---|---|
v7.5.0 | Поддержка значений, превышающих диапазон 32-битных беззнаковых целых чисел. |
v6.0.0 | Добавлено в: v6.0.0 |
- Возвращает: <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
}
]
v8.getHeapStatistics()
[История]
Версия | Изменения |
---|---|
v7.5.0 | Поддержка значений, превышающих диапазон 32-битного беззнакового целого числа. |
v7.2.0 | Добавлены malloced_memory , peak_malloced_memory и does_zap_garbage . |
v1.0.0 | Добавлено в: v1.0.0 |
- Возвращает: <Объект>
Возвращает объект со следующими свойствами:
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
<число>
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 (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
}
v8.queryObjects(ctor[, options])
Добавлено в: v22.0.0, v20.13.0
[Стабильность: 1 - Экспериментально]
Стабильность: 1 Стабильность: 1.1 - Активная разработка
ctor
<Function> Конструктор, который можно использовать для поиска по цепочке прототипов с целью фильтрации целевых объектов в куче.options
<undefined> | <Object>format
<string> Если это'count'
, возвращается количество найденных объектов. Если это'summary'
, возвращается массив с краткими строковыми представлениями найденных объектов.
Возвращает:
Это аналогично API консоли queryObjects()
, предоставляемому консолью Chromium DevTools. Его можно использовать для поиска объектов, имеющих совпадающий конструктор в цепочке прототипов в куче после полной сборки мусора, что может быть полезно для регрессионного тестирования утечек памяти. Чтобы избежать неожиданных результатов, пользователи должны избегать использования этого API для конструкторов, реализацию которых они не контролируют, или для конструкторов, которые могут вызываться другими участниками приложения.
Чтобы избежать случайных утечек, этот API не возвращает необработанные ссылки на найденные объекты. По умолчанию он возвращает количество найденных объектов. Если options.format
равен 'summary'
, он возвращает массив, содержащий краткие строковые представления для каждого объекта. Предоставляемая этим API видимость аналогична той, что предоставляет снимок кучи, при этом пользователи могут сэкономить на стоимости сериализации и анализа и напрямую фильтровать целевые объекты во время поиска.
В результаты включаются только объекты, созданные в текущем контексте выполнения.
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' }))
// Обратите внимание, что когда есть дочерние классы, наследующие от конструктора,
// конструктор также отображается в цепочке прототипов прототипа дочерних классов,
// поэтому прототип дочерних классов также будет включен в результат.
console.log(queryObjects(A)) // 3
// [ "B { foo: 'bar', bar: 'qux' }", 'A {}', "A { foo: 'bar' }" ]
console.log(queryObjects(A, { format: 'summary' }))
import { queryObjects } from 'node:v8'
class A {
foo = 'bar'
}
console.log(queryObjects(A)) // 0
const a = new A()
console.log(queryObjects(A)) // 1
// [ "A { foo: 'bar' }" ]
console.log(queryObjects(A, { format: 'summary' }))
class B extends A {
bar = 'qux'
}
const b = new B()
console.log(queryObjects(B)) // 1
// [ "B { foo: 'bar', bar: 'qux' }" ]
console.log(queryObjects(B, { format: 'summary' }))
// Обратите внимание, что когда есть дочерние классы, наследующие от конструктора,
// конструктор также отображается в цепочке прототипов прототипа дочерних классов,
// поэтому прототип дочерних классов также будет включен в результат.
console.log(queryObjects(A)) // 3
// [ "B { foo: 'bar', bar: 'qux' }", 'A {}', "A { foo: 'bar' }" ]
console.log(queryObjects(A, { format: 'summary' }))
v8.setFlagsFromString(flags)
Добавлено в: v1.0.0
flags
<string>
Метод v8.setFlagsFromString()
можно использовать для программной установки флагов командной строки V8. Этот метод следует использовать с осторожностью. Изменение настроек после запуска виртуальной машины может привести к непредсказуемому поведению, включая сбои и потерю данных; или же это может просто ничего не сделать.
Доступные для данной версии Node.js параметры V8 можно определить, запустив node --v8-options
.
Использование:
// Вывод событий GC в stdout в течение одной минуты.
const v8 = require('node:v8')
v8.setFlagsFromString('--trace_gc')
setTimeout(() => {
v8.setFlagsFromString('--notrace_gc')
}, 60e3)
v8.stopCoverage()
Добавлено в: v15.1.0, v14.18.0, v12.22.0
Метод v8.stopCoverage()
позволяет пользователю остановить сбор данных о покрытии, запущенный с помощью NODE_V8_COVERAGE
, чтобы V8 мог освободить записи счётчиков выполнения и оптимизировать код. Это можно использовать в сочетании с v8.takeCoverage()
, если пользователь хочет собирать данные о покрытии по запросу.
v8.takeCoverage()
Добавлено в: v15.1.0, v14.18.0, v12.22.0
Метод v8.takeCoverage()
позволяет пользователю по запросу записать данные о покрытии, запущенном с помощью NODE_V8_COVERAGE
, на диск. Этот метод может вызываться несколько раз за время существования процесса. Каждый раз счётчик выполнения будет сброшен, и новый отчёт о покрытии будет записан в каталог, указанный с помощью NODE_V8_COVERAGE
.
Когда процесс собирается завершиться, последний отчёт о покрытии всё равно будет записан на диск, если метод v8.stopCoverage()
не был вызван до завершения процесса.
v8.writeHeapSnapshot([filename[,options]])
[История]
Версия | Изменения |
---|---|
v19.1.0 | Поддержка параметров для настройки снимка кучи. |
v18.0.0 | Теперь будет выброшено исключение, если файл не может быть записан. |
v18.0.0 | Обеспечение согласованности возвращаемых кодов ошибок на всех платформах. |
v11.13.0 | Добавлено в: v11.13.0 |
filename
<string> Путь к файлу, в который будет сохранён снимок кучи V8. Если не указано, будет сгенерировано имя файла по шаблону'Heap-${yyyymmdd}-${hhmmss}-${pid}-${thread_id}.heapsnapshot'
, где{pid}
будет PID процесса Node.js,{thread_id}
будет0
, когдаwriteHeapSnapshot()
вызывается из основного потока Node.js, или ID потока worker.options
<Object>Возвращает: <string> Имя файла, в который был сохранён снимок.
Создаёт снимок текущей кучи V8 и записывает его в JSON-файл. Этот файл предназначен для использования с такими инструментами, как Chrome DevTools. JSON-схема не документирована и специфична для движка V8, и может меняться от одной версии V8 к другой.
Снимок кучи специфичен для одного изолята V8. При использовании потоков worker снимок кучи, созданный из основного потока, не будет содержать никакой информации о worker'ах, и наоборот.
Для создания снимка кучи требуется память примерно в два раза больше размера кучи на момент создания снимка. Это приводит к риску завершения процесса средствами 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}`)
// Теперь получим дамп кучи для основного потока.
console.log(`main thread heapdump: ${writeHeapSnapshot()}`)
})
// Скажем worker'у создать дамп кучи.
worker.postMessage('heapdump')
} else {
parentPort.once('message', message => {
if (message === 'heapdump') {
// Сгенерируем дамп кучи для worker'а
// и вернём имя файла родителю.
parentPort.postMessage(writeHeapSnapshot())
}
})
}
v8.setHeapSnapshotNearHeapLimit(limit)
Добавлено в: v18.10.0, v16.18.0
[Стабильно: 1 - Экспериментально]
Стабильно: 1 Стабильность: 1 - Экспериментально
limit
<целое число>
API является операцией без действия, если --heapsnapshot-near-heap-limit
уже установлен из командной строки или API вызывается более одного раза. limit
должно быть положительным целым числом. См. --heapsnapshot-near-heap-limit
для получения дополнительной информации.
API сериализации
API сериализации предоставляет средства сериализации значений JavaScript таким образом, который совместим с алгоритмом структурированного клонирования HTML.
Формат обратно совместим (т.е. безопасен для хранения на диске). Равные значения JavaScript могут привести к различным сериализованным результатам.
v8.serialize(value)
Добавлено в: v8.0.0
Использует DefaultSerializer
для сериализации value
в буфер.
ERR_BUFFER_TOO_LARGE
будет выброшено при попытке сериализовать огромный объект, который требует буфера большего размера, чем buffer.constants.MAX_LENGTH
.
v8.deserialize(buffer)
Добавлено в: v8.0.0
buffer
<Buffer> | <TypedArray> | <DataView> Буфер, возвращенныйserialize()
.
Использует DefaultDeserializer
с параметрами по умолчанию для чтения значения JS из буфера.
Класс: v8.Serializer
Добавлено в: v8.0.0
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>
Запись значения JS number
. Для использования внутри пользовательского 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
Добавлено в: v8.0.0
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()
в случае SharedArrayBuffer
).
deserializer.getWireFormatVersion()
- Возвращает: <целое число>
Считывает версию базового формата данных. Вероятно, в основном будет полезна для устаревшего кода, считывающего старые версии формата данных. Может не вызываться до .readHeader()
.
deserializer.readUint32()
- Возвращает: <целое число>
Считывает необработанное 32-битное беззнаковое целое число и возвращает его. Для использования внутри пользовательского deserializer._readHostObject()
.
deserializer.readUint64()
- Возвращает: <массив целых чисел>
Считывает необработанное 64-битное беззнаковое целое число и возвращает его как массив [hi, lo]
с двумя 32-битными беззнаковыми целыми числами. Для использования внутри пользовательского deserializer._readHostObject()
.
deserializer.readDouble()
- Возвращает: <число>
Считывает значение типа number
в JS. Для использования внутри пользовательского deserializer._readHostObject()
.
deserializer.readRawBytes(length)
length
<целое число>- Возвращает: <Buffer>
Считывает необработанные байты из внутреннего буфера десериализатора. Параметр length
должен соответствовать длине буфера, переданного в serializer.writeRawBytes()
. Для использования внутри пользовательского deserializer._readHostObject()
.
deserializer._readHostObject()
Этот метод вызывается для чтения некоторого объекта хоста, то есть объекта, созданного привязками нативного C++. Если десериализовать данные невозможно, должно быть выброшено соответствующее исключение.
Этот метод отсутствует в самом классе Deserializer
, но может быть предоставлен подклассами.
Класс: v8.DefaultSerializer
Добавлено в: v8.0.0
Подкласс Serializer
, который сериализует объекты TypedArray
(в частности, Buffer
) и DataView
как объекты хоста и хранит только ту часть их базовых ArrayBuffer
, на которую они ссылаются.
Класс: v8.DefaultDeserializer
Добавлено в: v8.0.0
Подкласс Deserializer
, соответствующий формату, записанному DefaultSerializer
.
Хуки Promise
Интерфейс promiseHooks
может использоваться для отслеживания событий жизненного цикла promise. Для отслеживания всей асинхронной активности см. async_hooks
, который внутренне использует этот модуль для генерации событий жизненного цикла promise в дополнение к событиям для других асинхронных ресурсов. Для управления контекстом запроса см. AsyncLocalStorage
.
import { promiseHooks } from 'node:v8'
// Существует четыре события жизненного цикла, генерируемых promise:
// Событие `init` представляет создание promise. Это может быть прямое создание, например, с помощью `new Promise(...)`, или продолжение, такое как `then()` или `catch()`. Это также происходит всякий раз, когда вызывается асинхронная функция или выполняется `await`. Если создается promise-продолжение, `parent` будет promise, от которого оно является продолжением.
function init(promise, parent) {
console.log('promise был создан', { promise, parent })
}
// Событие `settled` происходит, когда promise получает значение разрешения или отклонения. Это может произойти синхронно, например, при использовании `Promise.resolve()` для не-promise ввода.
function settled(promise) {
console.log('promise разрешен или отклонен', { promise })
}
// Событие `before` запускается непосредственно перед запуском обработчика `then()` или `catch()` или возобновлением выполнения `await`.
function before(promise) {
console.log('promise собирается вызвать обработчик then', { promise })
}
// Событие `after` запускается непосредственно после запуска обработчика `then()` или когда `await` начинается после возобновления с другого.
function after(promise) {
console.log('promise завершил вызов обработчика then', { promise })
}
// Хуки жизненного цикла могут запускаться и останавливаться по отдельности
const stopWatchingInits = promiseHooks.onInit(init)
const stopWatchingSettleds = promiseHooks.onSettled(settled)
const stopWatchingBefores = promiseHooks.onBefore(before)
const stopWatchingAfters = promiseHooks.onAfter(after)
// Или они могут запускаться и останавливаться группами
const stopHookSet = promiseHooks.createHook({
init,
settled,
before,
after,
})
// Чтобы остановить хук, вызовите функцию, возвращенную при его создании.
stopWatchingInits()
stopWatchingSettleds()
stopWatchingBefores()
stopWatchingAfters()
stopHookSet()
promiseHooks.onInit(init)
Добавлено в: v17.1.0, v16.14.0
init
<Function> Вызываемый методinit
, вызываемый при создании промиса.- Возвращает: <Function> Вызов для остановки хука.
Хук init
должен быть обычной функцией. Предоставление асинхронной функции приведёт к ошибке, так как это создаст бесконечный цикл микрозадач.
import { promiseHooks } from 'node:v8'
const stop = promiseHooks.onInit((promise, parent) => {})
const { promiseHooks } = require('node:v8')
const stop = promiseHooks.onInit((promise, parent) => {})
promiseHooks.onSettled(settled)
Добавлено в: v17.1.0, v16.14.0
settled
<Function> Вызываемый методsettled
, вызываемый при разрешении или отклонении промиса.- Возвращает: <Function> Вызов для остановки хука.
Хук settled
должен быть обычной функцией. Предоставление асинхронной функции приведёт к ошибке, так как это создаст бесконечный цикл микрозадач.
import { promiseHooks } from 'node:v8'
const stop = promiseHooks.onSettled(promise => {})
const { promiseHooks } = require('node:v8')
const stop = promiseHooks.onSettled(promise => {})
promiseHooks.onBefore(before)
Добавлено в: v17.1.0, v16.14.0
before
<Function> Вызываемый методbefore
, вызываемый перед выполнением продолжения промиса.- Возвращает: <Function> Вызов для остановки хука.
Хук before
должен быть обычной функцией. Предоставление асинхронной функции приведёт к ошибке, так как это создаст бесконечный цикл микрозадач.
import { promiseHooks } from 'node:v8'
const stop = promiseHooks.onBefore(promise => {})
const { promiseHooks } = require('node:v8')
const stop = promiseHooks.onBefore(promise => {})
promiseHooks.onAfter(after)
Добавлено в: v17.1.0, v16.14.0
after
<Function> Обратный вызовafter
, вызываемый после выполнения продолжения promise.- Возвращает: <Function> Вызов для остановки хука.
Хук after
должен быть простой функцией. Предоставление асинхронной функции приведёт к ошибке, так как это создаст бесконечный цикл микрозадач.
import { promiseHooks } from 'node:v8'
const stop = promiseHooks.onAfter(promise => {})
const { promiseHooks } = require('node:v8')
const stop = promiseHooks.onAfter(promise => {})
promiseHooks.createHook(callbacks)
Добавлено в: v17.1.0, v16.14.0
callbacks
<Object> Обратные вызовы хука для регистрацииinit
<Function> Обратный вызовinit
.before
<Function> Обратный вызовbefore
.after
<Function> Обратный вызовafter
.settled
<Function> Обратный вызовsettled
.
Возвращает: <Function> Используется для отключения хуков
Обратные вызовы хука должны быть простыми функциями. Предоставление асинхронных функций приведёт к ошибке, так как это создаст бесконечный цикл микрозадач.
Регистрирует функции, которые будут вызываться для различных событий жизненного цикла каждого promise.
Обратные вызовы init()
/before()
/after()
/settled()
вызываются для соответствующих событий во время жизненного цикла promise.
Все обратные вызовы являются необязательными. Например, если необходимо отслеживать только создание promise, то необходимо передать только обратный вызов init
. Специфика всех функций, которые могут быть переданы в callbacks
, находится в разделе Обратные вызовы хука.
import { promiseHooks } from 'node:v8'
const stopAll = promiseHooks.createHook({
init(promise, parent) {},
})
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 являются многопользовательскими и, следовательно, могут генерировать события в любом порядке относительно друг друга.
init(promise, parent)
promise
<Promise> Создаваемый промис.parent
<Promise> Промис, от которого произошло продолжение, если применимо.
Вызывается при создании промиса. Это не означает, что соответствующие события before
/after
произойдут, только что существует такая возможность. Это произойдет, если промис создается, но никогда не получает продолжения.
before(promise)
promise
<Promise>
Вызывается перед выполнением продолжения промиса. Это может быть в виде обработчиков then()
, catch()
или finally()
или возобновления await
.
Обратный вызов before
будет вызываться от 0 до N раз. Обратный вызов before
обычно вызывается 0 раз, если для промиса никогда не было сделано продолжение. Обратный вызов before
может вызываться много раз в случае, если из одного и того же промиса было сделано много продолжений.
after(promise)
promise
<Promise>
Вызывается сразу после выполнения продолжения promise. Это может быть после обработчика then()
, catch()
или finally()
или перед await
после другого await
.
settled(promise)
promise
<Promise>
Вызывается, когда promise получает значение разрешения или отклонения. Это может произойти синхронно в случае Promise.resolve()
или Promise.reject()
.
API моментального снимка запуска
Добавлено в: v18.6.0, v16.17.0
[Стабильно: 1 - Экспериментально]
Стабильно: 1 Стабильность: 1 - Экспериментально
Интерфейс v8.startupSnapshot
может использоваться для добавления хуков сериализации и десериализации для пользовательских моментальных снимков запуска.
$ node --snapshot-blob snapshot.blob --build-snapshot entry.js
# Запуск процесса со снимком {#this-launches-a-process-with-the-snapshot}
$ node --snapshot-blob snapshot.blob
В приведенном выше примере 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()
// Чтение серии файлов из каталога и сохранение их в хранилище.
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 здесь - это местоположение скрипта снимка
// во время построения снимка.
const shelf = new BookShelf(__dirname, ['book1.en_US.txt', 'book1.es_ES.txt', 'book2.zh_CN.txt'])
assert(v8.startupSnapshot.isBuildingSnapshot())
// При сериализации снимка сжимаем книги для уменьшения размера.
v8.startupSnapshot.addSerializeCallback(BookShelf.compressAll, shelf)
// При десериализации снимка распаковываем книги.
v8.startupSnapshot.addDeserializeCallback(BookShelf.decompressAll, shelf)
v8.startupSnapshot.setDeserializeMainFunction(shelf => {
// process.env и process.argv обновляются во время
// десериализации снимка.
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)
Получившийся двоичный файл выведет данные, десериализованные из снимка во время запуска, используя обновленные process.env
и process.argv
запущенного процесса:
$ BOOK_LANG=es_ES node --snapshot-blob snapshot.blob book1
# Выводит содержимое book1.es_ES.txt, десериализованное из снимка. {#prints-content-of-book1es_estxt-deserialized-from-the-snapshot}
В настоящее время приложение, десериализованное из снимка на уровне пользователя, не может быть снова снято, поэтому эти API доступны только приложениям, которые не десериализованы из снимка на уровне пользователя.
v8.startupSnapshot.addSerializeCallback(callback[, data])
Добавлено в: v18.6.0, v16.17.0
callback
<Function> Обратный вызов, который будет вызван перед сериализацией.data
<any> Необязательные данные, которые будут переданы вcallback
при его вызове.
Добавляет обратный вызов, который будет вызван, когда экземпляр Node.js собирается сериализоваться в снимок и завершить работу. Это может использоваться для освобождения ресурсов, которые не должны или не могут быть сериализованы, или для преобразования пользовательских данных в форму, более подходящую для сериализации.
Обратные вызовы выполняются в том порядке, в котором они были добавлены.
v8.startupSnapshot.addDeserializeCallback(callback[, data])
Добавлено в: v18.6.0, v16.17.0
callback
<Function> Обратный вызов, который будет вызван после десериализации снимка.data
<any> Необязательные данные, которые будут переданы вcallback
при его вызове.
Добавляет обратный вызов, который будет вызван, когда экземпляр Node.js десериализуется из снимка. callback
и data
(если предоставлены) будут сериализованы в снимок; они могут использоваться для повторной инициализации состояния приложения или для повторного получения ресурсов, необходимых приложению при перезапуске из снимка.
Обратные вызовы выполняются в том порядке, в котором они были добавлены.
v8.startupSnapshot.setDeserializeMainFunction(callback[, data])
Добавлено в: v18.6.0, v16.17.0
callback
<Function> Обратный вызов, который будет вызван в качестве точки входа после десериализации снимка.data
<any> Необязательные данные, которые будут переданы вcallback
при его вызове.
Это устанавливает точку входа приложения Node.js при его десериализации из снимка. Это может быть вызвано только один раз в скрипте построения снимка. Если вызывается, десериализованному приложению больше не требуется дополнительный скрипт точки входа для запуска, и оно просто вызовет обратный вызов вместе с десериализованными данными (если предоставлены), в противном случае десериализованному приложению все еще необходимо предоставить скрипт точки входа.
v8.startupSnapshot.isBuildingSnapshot()
Добавлено в: v18.6.0, v16.17.0
- Возвращает: <boolean>
Возвращает true, если экземпляр Node.js запущен для построения снимка.
Класс: v8.GCProfiler
Добавлено в: v19.6.0, v18.15.0
Этот API собирает данные GC в текущем потоке.
new v8.GCProfiler()
Добавлено в: v19.6.0, v18.15.0
Создает новый экземпляр класса v8.GCProfiler
.
profiler.start()
Добавлено в: v19.6.0, v18.15.0
Начинает сбор данных GC.
profiler.stop()
Добавлено в: v19.6.0, v18.15.0
Останавливает сбор данных 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
}
Пример.
const { GCProfiler } = require('node:v8')
const profiler = new GCProfiler()
profiler.start()
setTimeout(() => {
console.log(profiler.stop())
}, 1000)