Skip to content

Commit 47b0215

Browse files
make N-API examples context-sensitive (#141)
1 parent dc86a66 commit 47b0215

6 files changed

Lines changed: 109 additions & 34 deletions

File tree

6_object_wrap/napi/myobject.cc

Lines changed: 35 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,6 @@
11
#include "myobject.h"
22
#include <assert.h>
33

4-
napi_ref MyObject::constructor;
5-
64
MyObject::MyObject(double value)
75
: value_(value), env_(nullptr), wrapper_(nullptr) {}
86

@@ -32,14 +30,46 @@ napi_value MyObject::Init(napi_env env, napi_value exports) {
3230
env, "MyObject", NAPI_AUTO_LENGTH, New, nullptr, 3, properties, &cons);
3331
assert(status == napi_ok);
3432

35-
status = napi_create_reference(env, cons, 1, &constructor);
33+
// We will need the constructor `cons` later during the life cycle of the
34+
// addon, so we store a persistent reference to it as the instance data for
35+
// our addon. This will enable us to use `napi_get_instance_data` at any
36+
// point during the life cycle of our addon to retrieve it. We cannot simply
37+
// store it as a global static variable, because that will render our addon
38+
// unable to support Node.js worker threads and multiple contexts on a single
39+
// thread.
40+
//
41+
// The finalizer we pass as a lambda will be called when our addon is unloaded
42+
// and is responsible for releasing the persistent reference and freeing the
43+
// heap memory where we stored the persistent reference.
44+
napi_ref* constructor = new napi_ref;
45+
status = napi_create_reference(env, cons, 1, constructor);
46+
assert(status == napi_ok);
47+
status = napi_set_instance_data(env, constructor,
48+
[](napi_env env, void* data, void* hint) {
49+
napi_ref* constructor = static_cast<napi_ref*>(data);
50+
napi_status status = napi_delete_reference(env, *constructor);
51+
assert(status == napi_ok);
52+
delete constructor;
53+
}, nullptr);
3654
assert(status == napi_ok);
3755

3856
status = napi_set_named_property(env, exports, "MyObject", cons);
3957
assert(status == napi_ok);
4058
return exports;
4159
}
4260

61+
napi_value MyObject::Constructor(napi_env env) {
62+
void* instance_data = nullptr;
63+
napi_status status = napi_get_instance_data(env, &instance_data);
64+
assert(status == napi_ok);
65+
napi_ref* constructor = static_cast<napi_ref*>(instance_data);
66+
67+
napi_value cons;
68+
status = napi_get_reference_value(env, *constructor, &cons);
69+
assert(status == napi_ok);
70+
return cons;
71+
}
72+
4373
napi_value MyObject::New(napi_env env, napi_callback_info info) {
4474
napi_status status;
4575

@@ -89,12 +119,8 @@ napi_value MyObject::New(napi_env env, napi_callback_info info) {
89119
const size_t argc = 1;
90120
napi_value argv[argc] = {args[0]};
91121

92-
napi_value cons;
93-
status = napi_get_reference_value(env, constructor, &cons);
94-
assert(status == napi_ok);
95-
96122
napi_value instance;
97-
status = napi_new_instance(env, cons, argc, argv, &instance);
123+
status = napi_new_instance(env, Constructor(env), argc, argv, &instance);
98124
assert(status == napi_ok);
99125

100126
return instance;
@@ -181,17 +207,13 @@ napi_value MyObject::Multiply(napi_env env, napi_callback_info info) {
181207
status = napi_unwrap(env, jsthis, reinterpret_cast<void**>(&obj));
182208
assert(status == napi_ok);
183209

184-
napi_value cons;
185-
status = napi_get_reference_value(env, constructor, &cons);
186-
assert(status == napi_ok);
187-
188210
const int kArgCount = 1;
189211
napi_value argv[kArgCount];
190212
status = napi_create_double(env, obj->value_ * multiple, argv);
191213
assert(status == napi_ok);
192214

193215
napi_value instance;
194-
status = napi_new_instance(env, cons, kArgCount, argv, &instance);
216+
status = napi_new_instance(env, Constructor(env), kArgCount, argv, &instance);
195217
assert(status == napi_ok);
196218

197219
return instance;

6_object_wrap/napi/myobject.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,8 @@ class MyObject {
1717
static napi_value SetValue(napi_env env, napi_callback_info info);
1818
static napi_value PlusOne(napi_env env, napi_callback_info info);
1919
static napi_value Multiply(napi_env env, napi_callback_info info);
20-
static napi_ref constructor;
20+
static inline napi_value Constructor(napi_env env);
21+
2122
double value_;
2223
napi_env env_;
2324
napi_ref wrapper_;

7_factory_wrap/napi/myobject.cc

Lines changed: 35 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,6 @@ void MyObject::Destructor(napi_env env,
1616
#define DECLARE_NAPI_METHOD(name, func) \
1717
{ name, 0, func, 0, 0, 0, napi_default, 0 }
1818

19-
napi_ref MyObject::constructor;
20-
2119
napi_status MyObject::Init(napi_env env) {
2220
napi_status status;
2321
napi_property_descriptor properties[] = {
@@ -29,8 +27,28 @@ napi_status MyObject::Init(napi_env env) {
2927
env, "MyObject", NAPI_AUTO_LENGTH, New, nullptr, 1, properties, &cons);
3028
if (status != napi_ok) return status;
3129

32-
status = napi_create_reference(env, cons, 1, &constructor);
33-
if (status != napi_ok) return status;
30+
// We will need the constructor `cons` later during the life cycle of the
31+
// addon, so we store a persistent reference to it as the instance data for
32+
// our addon. This will enable us to use `napi_get_instance_data` at any
33+
// point during the life cycle of our addon to retrieve it. We cannot simply
34+
// store it as a global static variable, because that will render our addon
35+
// unable to support Node.js worker threads and multiple contexts on a single
36+
// thread.
37+
//
38+
// The finalizer we pass as a lambda will be called when our addon is unloaded
39+
// and is responsible for releasing the persistent reference and freeing the
40+
// heap memory where we stored the persistent reference.
41+
napi_ref* constructor = new napi_ref;
42+
status = napi_create_reference(env, cons, 1, constructor);
43+
assert(status == napi_ok);
44+
status = napi_set_instance_data(env, constructor,
45+
[](napi_env env, void* data, void* hint) {
46+
napi_ref* constructor = static_cast<napi_ref*>(data);
47+
napi_status status = napi_delete_reference(env, *constructor);
48+
assert(status == napi_ok);
49+
delete constructor;
50+
}, nullptr);
51+
assert(status == napi_ok);
3452

3553
return napi_ok;
3654
}
@@ -69,6 +87,18 @@ napi_value MyObject::New(napi_env env, napi_callback_info info) {
6987
return jsthis;
7088
}
7189

90+
napi_value MyObject::Constructor(napi_env env) {
91+
void* instance_data = nullptr;
92+
napi_status status = napi_get_instance_data(env, &instance_data);
93+
assert(status == napi_ok);
94+
napi_ref* constructor = static_cast<napi_ref*>(instance_data);
95+
96+
napi_value cons;
97+
status = napi_get_reference_value(env, *constructor, &cons);
98+
assert(status == napi_ok);
99+
return cons;
100+
}
101+
72102
napi_status MyObject::NewInstance(napi_env env,
73103
napi_value arg,
74104
napi_value* instance) {
@@ -77,11 +107,7 @@ napi_status MyObject::NewInstance(napi_env env,
77107
const int argc = 1;
78108
napi_value argv[argc] = {arg};
79109

80-
napi_value cons;
81-
status = napi_get_reference_value(env, constructor, &cons);
82-
if (status != napi_ok) return status;
83-
84-
status = napi_new_instance(env, cons, argc, argv, instance);
110+
status = napi_new_instance(env, Constructor(env), argc, argv, instance);
85111
if (status != napi_ok) return status;
86112

87113
return napi_ok;

7_factory_wrap/napi/myobject.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ class MyObject {
1515
MyObject();
1616
~MyObject();
1717

18-
static napi_ref constructor;
18+
static inline napi_value Constructor(napi_env env);
1919
static napi_value New(napi_env env, napi_callback_info info);
2020
static napi_value PlusOne(napi_env env, napi_callback_info info);
2121
double counter_;

8_passing_wrapped/napi/myobject.cc

Lines changed: 35 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,6 @@ void MyObject::Destructor(napi_env env,
1313
reinterpret_cast<MyObject*>(nativeObject)->~MyObject();
1414
}
1515

16-
napi_ref MyObject::constructor;
17-
1816
napi_status MyObject::Init(napi_env env) {
1917
napi_status status;
2018

@@ -23,8 +21,28 @@ napi_status MyObject::Init(napi_env env) {
2321
env, "MyObject", NAPI_AUTO_LENGTH, New, nullptr, 0, nullptr, &cons);
2422
if (status != napi_ok) return status;
2523

26-
status = napi_create_reference(env, cons, 1, &constructor);
27-
if (status != napi_ok) return status;
24+
// We will need the constructor `cons` later during the life cycle of the
25+
// application, so we store a persistent reference to it as the instance data
26+
// for our addon. This will enable us to use `napi_get_instance_data` at any
27+
// point during the life cycle of our addon to retrieve it. We cannot simply
28+
// store it as a global static variable, because that will render our addon
29+
// unable to support Node.js worker threads and multiple contexts on a single
30+
// thread.
31+
//
32+
// The finalizer we pass as a lambda will be called when our addon is unloaded
33+
// and is responsible for releasing the persistent reference and freeing the
34+
// heap memory where we stored the persistent reference.
35+
napi_ref* constructor = new napi_ref;
36+
status = napi_create_reference(env, cons, 1, constructor);
37+
assert(status == napi_ok);
38+
status = napi_set_instance_data(env, constructor,
39+
[](napi_env env, void* data, void* hint) {
40+
napi_ref* constructor = static_cast<napi_ref*>(data);
41+
napi_status status = napi_delete_reference(env, *constructor);
42+
assert(status == napi_ok);
43+
delete constructor;
44+
}, nullptr);
45+
assert(status == napi_ok);
2846

2947
return napi_ok;
3048
}
@@ -63,6 +81,18 @@ napi_value MyObject::New(napi_env env, napi_callback_info info) {
6381
return jsthis;
6482
}
6583

84+
napi_value MyObject::Constructor(napi_env env) {
85+
void* instance_data = nullptr;
86+
napi_status status = napi_get_instance_data(env, &instance_data);
87+
assert(status == napi_ok);
88+
napi_ref* constructor = static_cast<napi_ref*>(instance_data);
89+
90+
napi_value cons;
91+
status = napi_get_reference_value(env, *constructor, &cons);
92+
assert(status == napi_ok);
93+
return cons;
94+
}
95+
6696
napi_status MyObject::NewInstance(napi_env env,
6797
napi_value arg,
6898
napi_value* instance) {
@@ -71,11 +101,7 @@ napi_status MyObject::NewInstance(napi_env env,
71101
const int argc = 1;
72102
napi_value argv[argc] = {arg};
73103

74-
napi_value cons;
75-
status = napi_get_reference_value(env, constructor, &cons);
76-
if (status != napi_ok) return status;
77-
78-
status = napi_new_instance(env, cons, argc, argv, instance);
104+
status = napi_new_instance(env, Constructor(env), argc, argv, instance);
79105
if (status != napi_ok) return status;
80106

81107
return napi_ok;

8_passing_wrapped/napi/myobject.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ class MyObject {
1616
MyObject();
1717
~MyObject();
1818

19-
static napi_ref constructor;
19+
static inline napi_value Constructor(napi_env env);
2020
static napi_value New(napi_env env, napi_callback_info info);
2121
double val_;
2222
napi_env env_;

0 commit comments

Comments
 (0)