mirror of
https://github.com/electron/electron.git
synced 2026-05-02 03:00:22 -04:00
docs: add destroy method to native addon tutorials to prevent hang on quit (#50561)
Native addons that hold persistent references to callbacks, emitters, and threadsafe functions prevent Electron from quitting cleanly since Electron 40.5.0 due to changes in Node.js shutdown behavior. This adds a `destroy()` method to all four native code tutorials (Swift macOS, Obj-C macOS, C++ Linux, C++ Win32) that releases these resources and must be called before app quit. The destroy method resets callback and emitter references and aborts the threadsafe function, allowing the addon's destructor to run properly. An [!IMPORTANT] note is added to each tutorial's JavaScript wrapper section explaining when and why to call destroy(). Fixes #50457 Signed-off-by: Asish Kumar <officialasishkumar@gmail.com>
This commit is contained in:
@@ -1097,7 +1097,8 @@ public:
|
||||
Napi::Function func = DefineClass(env, "CppLinuxAddon", {
|
||||
InstanceMethod("helloWorld", &CppAddon::HelloWorld),
|
||||
InstanceMethod("helloGui", &CppAddon::HelloGui),
|
||||
InstanceMethod("on", &CppAddon::On)
|
||||
InstanceMethod("on", &CppAddon::On),
|
||||
InstanceMethod("destroy", &CppAddon::Destroy)
|
||||
});
|
||||
|
||||
Napi::FunctionReference *constructor = new Napi::FunctionReference();
|
||||
@@ -1139,11 +1140,12 @@ private:
|
||||
|
||||
Here, we create a C++ class that inherits from `Napi::ObjectWrap<CppAddon>`:
|
||||
|
||||
`static Napi::Object Init` defines our JavaScript interface with three methods:
|
||||
`static Napi::Object Init` defines our JavaScript interface with four methods:
|
||||
|
||||
* `helloWorld`: A simple function to test the bridge
|
||||
* `helloGui`: The function to launch our GTK3 UI
|
||||
* `on`: A method to register event callbacks
|
||||
* `destroy`: A method to release all persistent references before app quit
|
||||
|
||||
The constructor initializes:
|
||||
|
||||
@@ -1354,7 +1356,8 @@ public:
|
||||
Napi::Function func = DefineClass(env, "CppLinuxAddon", {
|
||||
InstanceMethod("helloWorld", &CppAddon::HelloWorld),
|
||||
InstanceMethod("helloGui", &CppAddon::HelloGui),
|
||||
InstanceMethod("on", &CppAddon::On)
|
||||
InstanceMethod("on", &CppAddon::On),
|
||||
InstanceMethod("destroy", &CppAddon::Destroy)
|
||||
});
|
||||
|
||||
Napi::FunctionReference *constructor = new Napi::FunctionReference();
|
||||
@@ -1497,6 +1500,20 @@ private:
|
||||
callbacks.Value().Set(info[0].As<Napi::String>(), info[1].As<Napi::Function>());
|
||||
return env.Undefined();
|
||||
}
|
||||
|
||||
Napi::Value Destroy(const Napi::CallbackInfo &info)
|
||||
{
|
||||
callbacks.Reset();
|
||||
emitter.Reset();
|
||||
|
||||
if (tsfn_ != nullptr)
|
||||
{
|
||||
napi_release_threadsafe_function(tsfn_, napi_tsfn_abort);
|
||||
tsfn_ = nullptr;
|
||||
}
|
||||
|
||||
return info.Env().Undefined();
|
||||
}
|
||||
};
|
||||
|
||||
Napi::Object Init(Napi::Env env, Napi::Object exports)
|
||||
@@ -1547,6 +1564,10 @@ class CppLinuxAddon extends EventEmitter {
|
||||
return this.addon.helloGui()
|
||||
}
|
||||
|
||||
destroy() {
|
||||
this.addon.destroy()
|
||||
}
|
||||
|
||||
// Parse JSON and convert date to JavaScript Date object
|
||||
parse(payload) {
|
||||
const parsed = JSON.parse(payload)
|
||||
@@ -1569,8 +1590,12 @@ This wrapper:
|
||||
* Only loads on Linux platforms
|
||||
* Forwards events from C++ to JavaScript
|
||||
* Provides clean methods to call into C++
|
||||
* Provides a `destroy()` method to release native resources
|
||||
* Converts JSON data into proper JavaScript objects
|
||||
|
||||
> [!IMPORTANT]
|
||||
> You must call `destroy()` before the app quits (e.g. in the `will-quit` or `before-quit` event handler). Without this, persistent references to callbacks and the threadsafe function will prevent the native addon's destructor from running, causing Electron to hang on quit.
|
||||
|
||||
## 7) Building and testing the addon
|
||||
|
||||
With all files in place, you can build the addon:
|
||||
|
||||
Reference in New Issue
Block a user