JavaScript реализует динамическую модель памяти. Когда объекты становятся недостижимыми, они становятся кандидатами на освобождение сборщиком мусора, работающим в фоне.
Бывают ситуации, когда вам нужно гарантировать, что объекты, созданные вашим Node-API-кодом, остаются выделенными. В этом случае нужно явно создать ссылку на них. Для этого и предназначены классы ObjectReference и FunctionReference.
Ссылки на объекты и функции можно инстанцировать либо как Weak (слабую), либо как Persistent (постоянную).
Ссылка Persistent инициализирует внутренний счётчик ссылок в единицу, что предотвращает освобождение памяти объекта сборщиком мусора. Объект, на который ссылаются, будет оставаться в памяти на протяжении жизни ссылки Persistent.
Использовать ссылку Persistent имеет смысл, когда длительность ссылки известна заранее. Внутренний счётчик ссылок уменьшается при удалении ссылки Persistent. Это сделает объект, на который ссылаются, кандидатом на удаление, если внутренний счётчик ссылок дойдёт до нуля.
Самый распространённый случай использования ссылки Persistent — когда вы создаёте класс JavaScript в своём Node-API-коде и вам нужно гарантировать, что его конструктор останется выделенным движком среды выполнения JavaScript.
Для более сложных реализаций, где несколько AsyncWorker'ов полагаются на объект, на который ссылаются, может быть разумнее использовать ссылку Weak, которая инициализирует внутренний счётчик ссылок в ноль. Счётчик ссылок затем можно поддерживать с помощью методов Ref и Unref класса Reference.
Самый распространённый сценарий использования ссылки Weak — когда вашему Node-API-коду нужно отслеживать, когда созданный вами в Node-API-коде JavaScript-объект будет освобождён сборщиком мусора.
Класс ObjectReference наследуется от класса Reference. Ценность, которую он добавляет, — набор методов Get и Set, которые манипулируют свойствами объекта, на который ссылаются.
Как и ObjectReference, класс FunctionReference наследуется от класса Reference. Если класс ObjectReference добавляет методы Get и Set, то класс FunctionReference добавляет набор методов Call, реализующих вызовы функции.
Этот пример кода показывает, как использовать класс FunctionReference.
native-addon.h объявляет C++-класс NativeAddon, у которого два члена данных, заполняемых в конструкторе:
Napi::FunctionReference jsFnRefNapi::Function jsFn
native-addon.cc содержит реализацию NativeAddon. Конструктор, вызываемый из JavaScript, принимает два аргумента-функции. Первый аргумент сохраняется как Napi::FunctionReference, а второй — как Napi::Function.
В этом коде намеренная ошибка.
Вторая функция сохраняется в члене данных Napi::Function jsFn. Это ошибка, потому что время жизни второго аргумента ограничено временем жизни конструктора. Значение члена данных jsFn станет невалидным после возврата из конструктора. Первый аргумент сохраняется в Napi::FunctionReference jsFnRef. Благодаря использованию Napi::FunctionReference значение jsFnRef останется валидным после возврата из конструктора.
Класс NativeAddon реализует два метода, которые можно вызывать из JavaScript: TryCallByStoredReference и TryCallByStoredFunction. Обратите внимание, что метод Call используется одинаково и для члена данных jsFnRef, и для jsFn.
binding.cc — стандартный файл биндинга, регистрирующий класс NativeAddon в Node-API.
index.js показывает использование класса NativeAddon из JavaScript. Обратите внимание, что вызов нативного метода tryCallByStoredFunction падает, потому что член данных, на который он полагается, невалиден.