Мне сложно понять, как правильно использовать HandleScope и EscapableHandleScope. Например, из этот пример узла:
MyObject::MyObject(const Napi::CallbackInfo& info) : Napi::ObjectWrap<MyObject>(info) {
Napi::Env env = info.Env();
Napi::HandleScope scope(env);
this->val_ = info[0].As<Napi::Number>().DoubleValue();
};
Зачем нам в этом случае нужно создавать новый HandleScope? И из этот другой пример:
Napi::Object CreateObject(const Napi::CallbackInfo& info) {
Napi::Env env = info.Env();
Napi::Object obj = Napi::Object::New(env);
obj.Set(Napi::String::New(env, "msg"), info[0].ToString());
return obj;
}
Почему он здесь не нужен?
Кроме того, я не нашел ни одного примера использования EscapableHandleScope, когда это необходимо?





Для объяснения того, что такое HandleScopes и для чего их использовать, см. Документация V8, например. для класса Local:
There are two types of handles: local and persistent handles.
Local handles are light-weight and transient and typically used in local operations. They are managed by HandleScopes. That means that a HandleScope must exist on the stack when they are created and that they are only valid inside of the HandleScope active during their creation. For passing a local handle to an outer HandleScope, an EscapableHandleScope and its Escape() method must be used.
А для класса HandleScope:
A stack-allocated class that governs a number of local handles. After a handle scope has been created, all local handles will be allocated within that handle scope until either the handle scope is deleted or another handle scope is created. If there is already a handle scope and a new one is created, all allocations will take place in the new handle scope until it is deleted. After that, new handles will again be allocated in the original handle scope.
After the handle scope of a local handle has been deleted the garbage collector will no longer track the object stored in the handle and may deallocate it. The behavior of accessing a handle for which the handle scope has been deleted is undefined.
Прагматически:
HandleScope, если код C++ создает какие-либо Local<>. Обычно правильный номер - ровно один HandleScope.EscapableHandleScope, если вы хотите вернуть объект по истечении срока жизни области.Это не противоречит тому, что я написал. Вам всегда нужен HandleScope. Если какой-то уровень абстракции (например, NAPI) уже неявно создает один (эта «область по умолчанию», которую вы упомянули), то вам не нужно вручную создавать другой.
Но вопрос OP был конкретно о Node Addon API и Napi :: HandleScope, а не о V8 и v8 :: HandleScope.
Следующее кажется верным для nan, N-API и node-addon-api:
[Handle Scope] is an abstraction used to control and modify the lifetime of objects created within a particular scope. In general, N-API values are created within the context of a handle scope. When a native method is called from JavaScript, a default handle scope will exist. If the user does not explicitly create a new handle scope, N-API values will be created in the default handle scope. For any invocations of code outside the execution of a native method (for instance, during a libuv callback invocation), the module is required to create a scope before invoking any functions that can result in the creation of JavaScript values.
Источник: https://nodejs.org/api/n-api.html#n_api_napi_handle_scope
Это означает, что в приведенных примерах, поскольку оба ожидают const Napi::CallbackInfo& info, очевидно, что оба они вызываются напрямую из JavaScript, поэтому у них уже есть область действия, предоставляемая средой выполнения JS - дополнительные вызовы для создания области необходимы только в том случае, если вы хотите самостоятельно управлять памятью. или в тех случаях, когда ваш код выполняется независимо от JS-движка (например, по таймеру, обратный вызов от чего-то другого, кроме JS-кода и т. д.)
Фактически, мы можем не создавать здесь новый HandleScope. В Node.js есть внешняя область видимости, которая охватывает наши дескрипторы, созданные в этой функции. Но тогда все дескрипторы, созданные в этой функции, будут жить дольше, чем необходимо, и будут обрабатывать затратные ресурсы.
Когда дескриптор внутренней области видимости должен жить дольше, чем продолжительность жизни этой области. Например, при возврате данных, вновь созданных в функции.
Встраивание V8: https://v8.dev/docs/embed#handles-and-garbage-collection
узел-аддон-api: https://github.com/nodejs/node-addon-api/blob/master/doc/object_lifetime_management.md
Это неверно. HandleScope обычно не нужен на верхнем уровне метода C++. Процитируем документацию NAPI: «Продолжительность жизни для области по умолчанию привязана к продолжительности жизни вызова собственного метода. В результате, по умолчанию, дескрипторы остаются действительными, а объекты, связанные с этими дескрипторами, будут оставаться живыми в течение всего срока службы. вызов собственного метода ".