From e095c0168202f3424ce9ceefd206571bb5bc6347 Mon Sep 17 00:00:00 2001 From: Gabriel Schulhof Date: Mon, 29 Jun 2020 12:49:04 -0700 Subject: [PATCH] doc: update ObjectWrap example * 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: https://github.com/nodejs/node-addon-api/issues/711 --- doc/object_wrap.md | 48 +++++++++++++++++++++++++++++++--------------- 1 file changed, 33 insertions(+), 15 deletions(-) diff --git a/doc/object_wrap.md b/doc/object_wrap.md index cdf7ce1e2..0843092df 100644 --- a/doc/object_wrap.md +++ b/doc/object_wrap.md @@ -22,49 +22,57 @@ your C++ class methods. class Example : public Napi::ObjectWrap { 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(constructor); + return exports; } -Example::Example(const Napi::CallbackInfo &info) : Napi::ObjectWrap(info) { +Example::Example(const Napi::CallbackInfo& info) : Napi::ObjectWrap(info) { Napi::Env env = info.Env(); // ... Napi::Number value = info[0].As(); 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(); @@ -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(); + return constructor->New({ Napi::Number::New(info.Env(), 42) }); +} + // Register and initialize native add-on NODE_API_MODULE(NODE_GYP_MODULE_NAME, Init) ```