Skip to content

Commit

Permalink
doc: update ObjectWrap example
Browse files Browse the repository at this point in the history
* Remove the global static reference to the constructor
* Use `Napi::Env::SetInstanceData` to store the constructor, and
* Add a static method that uses `Napi::FunctionReference::New` to
  create a new instance of the class by retrieving the constructor
  using `Napi::Env::GetInstanceData` and using
  `Napi::FunctionReference::New` to create the new instance.

Fixes: nodejs/node-addon-api#711
PR-URL: nodejs/node-addon-api#754
Reviewed-By: Nicola Del Gobbo <nicoladelgobbo@gmail.com>
Reviewed-By: Anna Henningsen <anna@addaleax.net>
  • Loading branch information
kevindavies8 committed Jul 2, 2020
1 parent 8db38db commit 5228631
Showing 1 changed file with 33 additions and 15 deletions.
48 changes: 33 additions & 15 deletions doc/object_wrap.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,49 +22,57 @@ your C++ class methods.
class Example : public Napi::ObjectWrap<Example> {
public:
static Napi::Object Init(Napi::Env env, Napi::Object exports);
Example(const Napi::CallbackInfo &info);
Example(const Napi::CallbackInfo& info);
static Napi::Value CreateNewItem(const Napi::CallbackInfo& info);

private:
static Napi::FunctionReference constructor;
double _value;
Napi::Value GetValue(const Napi::CallbackInfo &info);
Napi::Value SetValue(const Napi::CallbackInfo &info);
Napi::Value GetValue(const Napi::CallbackInfo& info);
Napi::Value SetValue(const Napi::CallbackInfo& info);
};

Napi::Object Example::Init(Napi::Env env, Napi::Object exports) {
// This method is used to hook the accessor and method callbacks
Napi::Function func = DefineClass(env, "Example", {
InstanceMethod<&Example::GetValue>("GetValue"),
InstanceMethod<&Example::SetValue>("SetValue")
InstanceMethod<&Example::SetValue>("SetValue"),
StaticMethod<&Example::CreateNewItem>("CreateNewItem"),
});

Napi::FunctionReference* constructor = new Napi::FunctionReference();

// Create a peristent reference to the class constructor. This will allow
// a function called on a class prototype and a function
// called on instance of a class to be distinguished from each other.
constructor = Napi::Persistent(func);
// Call the SuppressDestruct() method on the static data prevent the calling
// to this destructor to reset the reference when the environment is no longer
// available.
constructor.SuppressDestruct();
*constructor = Napi::Persistent(func);
exports.Set("Example", func);

// Store the constructor as the add-on instance data. This will allow this
// add-on to support multiple instances of itself running on multiple worker
// threads, as well as multiple instances of itself running in different
// contexts on the same thread.
//
// By default, the value set on the environment here will be destroyed when
// the add-on is unloaded using the `delete` operator, but it is also
// possible to supply a custom deleter.
env.SetInstanceData<Napi::FunctionReference>(constructor);

return exports;
}

Example::Example(const Napi::CallbackInfo &info) : Napi::ObjectWrap<Example>(info) {
Example::Example(const Napi::CallbackInfo& info) : Napi::ObjectWrap<Example>(info) {
Napi::Env env = info.Env();
// ...
Napi::Number value = info[0].As<Napi::Number>();
this->_value = value.DoubleValue();
}

Napi::FunctionReference Example::constructor;

Napi::Value Example::GetValue(const Napi::CallbackInfo &info){
Napi::Value Example::GetValue(const Napi::CallbackInfo& info){
Napi::Env env = info.Env();
return Napi::Number::New(env, this->_value);
}

Napi::Value Example::SetValue(const Napi::CallbackInfo &info){
Napi::Value Example::SetValue(const Napi::CallbackInfo& info){
Napi::Env env = info.Env();
// ...
Napi::Number value = info[0].As<Napi::Number>();
Expand All @@ -78,6 +86,16 @@ Napi::Object Init (Napi::Env env, Napi::Object exports) {
return exports;
}

// Create a new item using the constructor stored during Init.
Napi::Value Example::CreateNewItem(const Napi::CallbackInfo& info) {
// Retrieve the instance data we stored during `Init()`. We only stored the
// constructor there, so we retrieve it here to create a new instance of the
// JS class the constructor represents.
Napi::FunctionReference* constructor =
info.Env().GetInstanceData<Napi::FunctionReference>();
return constructor->New({ Napi::Number::New(info.Env(), 42) });
}

// Register and initialize native add-on
NODE_API_MODULE(NODE_GYP_MODULE_NAME, Init)
```
Expand Down

0 comments on commit 5228631

Please sign in to comment.