Skip to content

Commit 979fb15

Browse files
Gabriel SchulhofMylesBorins
Gabriel Schulhof
authored andcommitted
doc: update context-aware section of addon doc
Replace the portion of the context-aware addon example that advocates for managing the life cycle of the per-addon-instance data using a weak reference with code that illustrates how to manage its life cycle using an environment cleanup hook. Signed-off-by: Gabriel Schulhof <[email protected]> PR-URL: #28659 Reviewed-By: Michael Dawson <[email protected]>
1 parent 5080491 commit 979fb15

File tree

1 file changed

+32
-29
lines changed

1 file changed

+32
-29
lines changed

doc/api/addons.md

+32-29
Original file line numberDiff line numberDiff line change
@@ -155,18 +155,25 @@ they were created.
155155
156156
The context-aware addon can be structured to avoid global static data by
157157
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.
170177
171178
This will ensure that the per-addon-instance data reaches each binding that can
172179
be called from JavaScript. The per-addon-instance data must also be passed into
@@ -181,25 +188,18 @@ using namespace v8;
181188
182189
class AddonData {
183190
public:
184-
AddonData(Isolate* isolate, Local<Object> exports):
191+
explicit AddonData(Isolate* isolate):
185192
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);
189195
}
190196
191197
// Per-addon data.
192198
int call_count;
193199
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);
198202
}
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_;
203203
};
204204
205205
static void Method(const v8::FunctionCallbackInfo<v8::Value>& info) {
@@ -214,14 +214,17 @@ static void Method(const v8::FunctionCallbackInfo<v8::Value>& info) {
214214
NODE_MODULE_INIT(/* exports, module, context */) {
215215
Isolate* isolate = context->GetIsolate();
216216
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.
220223
Local<External> external = External::New(isolate, data);
221224
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
223226
// 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.
225228
exports->Set(context,
226229
String::NewFromUtf8(isolate, "method", NewStringType::kNormal)
227230
.ToLocalChecked(),

0 commit comments

Comments
 (0)