@@ -155,18 +155,25 @@ they were created.
155
155
156
156
The context-aware addon can be structured to avoid global static data by
157
157
performing the following steps:
158
-
159
- * defining a class which will hold per-addon-instance data. Such
160
- a class should include a `v8::Global<v8::Object>` which will hold a weak
161
- reference to the addon's `exports` object. The callback associated with the weak
162
- reference will then destroy the instance of the class.
163
- * constructing an instance of this class in the addon initializer such that the
164
- `v8::Global<v8::Object>` is set to the `exports` object.
165
- * storing the instance of the class in a `v8::External`, and
166
- * passing the `v8::External` to all methods exposed to JavaScript by passing it
167
- to the `v8::FunctionTemplate` constructor which creates the native-backed
168
- JavaScript functions. The `v8::FunctionTemplate` constructor's third parameter
169
- accepts the `v8::External`.
158
+ * Define a class which will hold per-addon-instance data and which has a static
159
+ member of the form
160
+ ```C++
161
+ static void DeleteInstance(void* data) {
162
+ // Cast `data` to an instance of the class and delete it.
163
+ }
164
+ ```
165
+ * Heap-allocate an instance of this class in the addon initializer. This can be
166
+ accomplished using the `new` keyword.
167
+ * Call `node::AddEnvironmentCleanupHook()`, passing it the above-created
168
+ instance and a pointer to `DeleteInstance()`. This will ensure the instance is
169
+ deleted when the environment is torn down.
170
+ * Store the instance of the class in a `v8::External`, and
171
+ * Pass the `v8::External` to all methods exposed to JavaScript by passing it
172
+ to `v8::FunctionTemplate::New()` or `v8::Function::New()` which creates the
173
+ native-backed JavaScript functions. The third parameter of
174
+ `v8::FunctionTemplate::New()` or `v8::Function::New()` accepts the
175
+ `v8::External` and makes it available in the native callback using the
176
+ `v8::FunctionCallbackInfo::Data()` method.
170
177
171
178
This will ensure that the per-addon-instance data reaches each binding that can
172
179
be called from JavaScript. The per-addon-instance data must also be passed into
@@ -181,25 +188,18 @@ using namespace v8;
181
188
182
189
class AddonData {
183
190
public:
184
- AddonData(Isolate* isolate, Local<Object> exports ):
191
+ explicit AddonData(Isolate* isolate):
185
192
call_count(0) {
186
- // Link the existence of this object instance to the existence of exports.
187
- exports_.Reset(isolate, exports);
188
- exports_.SetWeak(this, DeleteMe, WeakCallbackType::kParameter);
193
+ // Ensure this per-addon-instance data is deleted at environment cleanup.
194
+ node::AddEnvironmentCleanupHook(isolate, DeleteInstance, this);
189
195
}
190
196
191
197
// Per-addon data.
192
198
int call_count;
193
199
194
- private:
195
- // Method to call when "exports" is about to be garbage-collected.
196
- static void DeleteMe(const WeakCallbackInfo<AddonData>& info) {
197
- delete info.GetParameter();
200
+ static void DeleteInstance(void* data) {
201
+ delete static_cast<AddonData*>(data);
198
202
}
199
-
200
- // Weak handle to the "exports" object. An instance of this class will be
201
- // destroyed along with the exports object to which it is weakly bound.
202
- v8::Global<v8::Object> exports_;
203
203
};
204
204
205
205
static void Method(const v8::FunctionCallbackInfo<v8::Value>& info) {
@@ -214,14 +214,17 @@ static void Method(const v8::FunctionCallbackInfo<v8::Value>& info) {
214
214
NODE_MODULE_INIT(/* exports, module, context */) {
215
215
Isolate* isolate = context->GetIsolate();
216
216
217
- // Create a new instance of AddonData for this instance of the addon.
218
- AddonData* data = new AddonData(isolate, exports);
219
- // Wrap the data in a v8::External so we can pass it to the method we expose.
217
+ // Create a new instance of `AddonData` for this instance of the addon and
218
+ // tie its life cycle to that of the Node.js environment.
219
+ AddonData* data = new AddonData(isolate);
220
+
221
+ // Wrap the data in a `v8::External` so we can pass it to the method we
222
+ // expose.
220
223
Local<External> external = External::New(isolate, data);
221
224
222
- // Expose the method " Method" to JavaScript, and make sure it receives the
225
+ // Expose the method ` Method` to JavaScript, and make sure it receives the
223
226
// per-addon-instance data we created above by passing `external` as the
224
- // third parameter to the FunctionTemplate constructor.
227
+ // third parameter to the ` FunctionTemplate` constructor.
225
228
exports->Set(context,
226
229
String::NewFromUtf8(isolate, "method", NewStringType::kNormal)
227
230
.ToLocalChecked(),
0 commit comments