node-addon-api
node-addon-api copied to clipboard
Emit wrapped instance to Javascript from C++ constructor
Hello,
Thanks to this post, I was able to embed a simple event listener in my class.
Basically, on JS call of a static On
method, my wrapped class records a callback function in a std::map
.
std::map<std::string, std::vector<Napi::ThreadSafeFunction>> MyWrapper::s_listeners;
void MyWrapper::On(const Napi::CallbackInfo &info)
{
Napi::Env env = info.Env();
// Get channel name.
std::string channel = info[0].As<Napi::String>().Utf8Value();
// Unique callback name.
std::string callback_name = channel + "_callback_" + std::to_string(MyWrapper::s_callbacks_count);
MyWrapper::s_callbacks_count += 1;
// Actual callback.
Napi::Function fn = info[1].As<Napi::Function>();
Napi::ThreadSafeFunction callback = Napi::ThreadSafeFunction::New(env, fn, callback_name, 0, 1);
// Push callback for this channel.
MyWrapper::s_listeners[channel].push_back(callback);
}
Then, when creating a new MyWrapper
instance, I call another static function to trigger the registered callbacks.
MyWrapper::MyWrapper(const Napi::CallbackInfo& info)
: Napi::ObjectWrap<MyWrapper>(info)
{
Napi::Env env = info.Env();
Napi::HandleScope scope(env);
try {
// ... omitted for brevity...
// Trigger eventual listeners.
MyWrapper::_OnInstanceCreated(info);
} catch (char const *err)
{
Napi::TypeError::New(env, err).ThrowAsJavaScriptException();
}
}
void MyWrapper::_OnInstanceCreated(const Napi::CallbackInfo &info) {
// Channel name.
const char * channel = "created";
// printf("IsConstructCall %i\n", info.IsConstructCall()); // Returns true.
Napi::Function n_server = info.NewTarget().As<Napi::Function>(); // FIXME: Returns number in JS.
// Find registered callbacks.
auto channel_callbacks = MyWrapper::s_listeners.find(channel);
if (channel_callbacks != MyWrapper::s_listeners.end()) {
std::vector<Napi::ThreadSafeFunction> callbacks = channel_callbacks->second;
for (auto it = begin(callbacks); it != end(callbacks); ++it) {
// Calls registered callback.
auto callback = [n_server](Napi::Env env, Napi::Function js_callback) {
js_callback.Call({n_server});
};
it->NonBlockingCall(callback);
}
}
}
On Javascript side, I register the listener
MyAddon.MyClass.on('created', (myInstance: any) => {
console.log(myInstance); // Returns a number of... 32759 (???)
});
Listener is correctly called, but myInstance parameter returns a number... What does this mean? Am I correctly getting the instance through info.NewTarget()
? Is this that when caching the callback I'm missing something (in info[1].As<Napi::Function>()
)?
Basically, I try to get the newly created instance and forward it to my listener.
How can I get it? Is the wrapped object already created when I call the _OnInstanceCreated
function? Is there a way to do this that I'm missing?
Any help would be highly appreciated!
Thank you!