I'm writing a c++ addon for node using NAN, but I'm confused how to correctly use Nan::HandleScope (https://github.com/nodejs/nan/blob/master/doc/scopes.md#api_nan_handle_scope)
In my application I'm doing something like this (error checking removed, and only simplified version of code is shown):
static App* s_pApp = nullptr;
NAN_METHOD( init ) {
s_pApp = new App();
}
NAN_METHOD( getData ) {
info.GetReturnValue().Set( s_pApp->getData() );
}
NAN_METHOD( close ) {
delete s_pApp;
s_pApp = nullptr;
}
//-------- This create a new json object based on the current state of _pRootNode which is a TreeNode class object previously populated
v8::Local<v8::Object> App::getData() const {
Nan::EscapableHandleScope scope;
v8::Local<v8::Object> obj = _pRootNode->getData();
return scope.Escape( obj );
}
//-------- The TreeNode class
v8::Local<v8::Object> TreeNode::getData() const {
return getData( this );
}
//each node contains data plus a vector of children that are also TreeNodes
v8::Local<v8::Object> TreeNode::getData( const TreeNode* pNode ) const {
v8::Local<v8::Object> jsonObject = Nan::New<v8::Object>();
addProperty( jsonObject, "isImportant", _isImportant );
addProperty( jsonObject, "value", _value );
addProperty( jsonObject, _children );
return jsonObject;
}
//The addProperty functions are used to populate the jsonObject which will eventually be returned back to JavaScript
template<class T>
void TreeNode::addProperty( v8::Local<v8::Object>& jsonObject, const char* szName, T propValue ) {
v8::Local<v8::String> prop = Nan::New( szName ).ToLocalChecked();
v8::Local<v8::Value> value = getValue( propValue ); //returns the appropriate v8 value
Nan::Set( jsonObject, prop, value );
}
void TreeNode::addProperty( v8::Local<v8::Object>& jsonObject, const std::vector<const TreeNode*>& children ) {
if( children.empty() ) {
return;
}
v8::Local<v8::String> prop = Nan::New( "children" ).ToLocalChecked();
v8::Local<v8::Array> values = Nan::New<v8::Array>( children.size() );
for( int i = 0, numChildren = children.size(); i < numChildren; ++i ) {
values->Set( i, children.at( i )->getData() ); //recursive call
}
Nan::Set( jsonObject, prop, values );
}
So as we can see in the code above, The only place that I'm handling scope is in the App::getData() call which returns the json object that is created by the TreeNode class. Is this correct? Or should I be using HandleScope everywhere that Nan::New is called? Or should it also be using EscapableHandleScope rather than HandleScope since I actually want to be returning the values that are generated?
Taken directly from the documentation markdown:
Nan::HandleScope
- https://github.com/nodejs/nan/blob/master/doc/scopes.md#api_nan_handle_scope :
Allocate a new Nan::HandleScope whenever you are creating new V8 JavaScript objects. Note that an implicit HandleScope is created for you on JavaScript-accessible methods so you do not need to insert one yourself.
Nan::EscapableHandleScope
- https://github.com/nodejs/nan/blob/master/doc/scopes.md#api_nan_escapable_handle_scope
Similar to Nan::HandleScope but should be used in cases where a function needs to return a V8 JavaScript type that has been created within it.
So, you were correct in using a Nan::EscapableHandleScope
within App::getData()
. However, I think this Nan::EscapableHandleScope
within App::getData()
could be moved to TreeNode::getData( const TreeNode* pNode )
, since that is the function that actually creates the V8 Javascript type.
I don't think there's anything wrong with what you did here, I would just tend to keep the Nan::HandleScope
/ Nan::EscapableHndleScope
closer to (preferably within) the function that creates the object being returned.