1# Object lifetime management 2 3A handle may be created when any new node-addon-api Value and 4its subclasses is created or returned. 5 6As the methods and classes within the node-addon-api are used, 7handles to objects in the heap for the underlying 8VM may be created. A handle may be created when any new 9node-addon-api Value or one of its subclasses is created or returned. 10These handles must hold the objects 'live' until they are no 11longer required by the native code, otherwise the objects could be 12collected by the garbage collector before the native code was 13finished using them. 14 15As handles are created they are associated with a 16'scope'. The lifespan for the default scope is tied to the lifespan 17of the native method call. The result is that, by default, handles 18remain valid and the objects associated with these handles will be 19held live for the lifespan of the native method call. 20 21In many cases, however, it is necessary that the handles remain valid for 22either a shorter or longer lifespan than that of the native method. 23The sections which follow describe the node-addon-api classes and 24methods that than can be used to change the handle lifespan from 25the default. 26 27## Making handle lifespan shorter than that of the native method 28 29It is often necessary to make the lifespan of handles shorter than 30the lifespan of a native method. For example, consider a native method 31that has a loop which creates a number of values and does something 32with each of the values, one at a time: 33 34```C++ 35for (int i = 0; i < LOOP_MAX; i++) { 36 std::string name = std::string("inner-scope") + std::to_string(i); 37 Napi::Value newValue = Napi::String::New(info.Env(), name.c_str()); 38 // do something with newValue 39}; 40``` 41 42This would result in a large number of handles being created, consuming 43substantial resources. In addition, even though the native code could only 44use the most recently created value, all of the previously created 45values would also be kept alive since they all share the same scope. 46 47To handle this case, node-addon-api provides the ability to establish 48a new 'scope' to which newly created handles will be associated. Once those 49handles are no longer required, the scope can be deleted and any handles 50associated with the scope are invalidated. The `Napi::HandleScope` 51and `Napi::EscapableHandleScope` classes are provided by node-addon-api for 52creating additional scopes. 53 54node-addon-api only supports a single nested hierarchy of scopes. There is 55only one active scope at any time, and all new handles will be associated 56with that scope while it is active. Scopes must be deleted in the reverse 57order from which they are opened. In addition, all scopes created within 58a native method must be deleted before returning from that method. Since 59`Napi::HandleScopes` are typically stack allocated the compiler will take care of 60deletion, however, care must be taken to create the scope in the right 61place such that you achieve the desired lifetime. 62 63Taking the earlier example, creating a `Napi::HandleScope` in the inner loop 64would ensure that at most a single new value is held alive throughout the 65execution of the loop: 66 67```C 68for (int i = 0; i < LOOP_MAX; i++) { 69 Napi::HandleScope scope(info.Env()); 70 std::string name = std::string("inner-scope") + std::to_string(i); 71 Napi::Value newValue = Napi::String::New(info.Env(), name.c_str()); 72 // do something with newValue 73}; 74``` 75 76When nesting scopes, there are cases where a handle from an 77inner scope needs to live beyond the lifespan of that scope. node-addon-api 78provides the `Napi::EscapableHandleScope` with the `Escape` method 79in order to support this case. An escapable scope 80allows one object to be 'promoted' so that it 'escapes' the 81current scope and the lifespan of the handle changes from the current 82scope to that of the outer scope. The `Escape` method can only be called 83once for a given `Napi::EscapableHandleScope`. 84