Hi,
I'm working on a project where I need to be capable of calling a javascript function whenever I need, from c++ code sending commands (or events) to my node server. I believe I can achieve that by storing a function reference using the corresponding napi class and I'm trying to write a prototype. Fact is, this seems rather complex based only on the current examples, so I'd like to kindly ask you (and suggest too) to share an example project including the following capabilities:
Its a suggestion, I think it would make things much more clear regarding the Reference class and callbacks. Appreciate any comments too!
HI @felipezacani,
you can use Napi::FuntionReference to store the JavaScript function. I report a little example below:
index.js
'use strict'
const { NativeAddon } = require('bindings')('addon')
function JSFunction() {
console.log('Hi I\'m a JS function!')
}
const nf = new NativeAddon(JSFunction)
nf.callInNativeFunction()
native-addon.h
#include <napi.h>
class NativeAddon : public Napi::ObjectWrap<NativeAddon> {
public:
static Napi::Object Init(Napi::Env env, Napi::Object exports);
NativeAddon(const Napi::CallbackInfo& info);
private:
static Napi::FunctionReference constructor;
Napi::FunctionReference js;
Napi::Value CallInNativeFunction(const Napi::CallbackInfo& info);
};
native-addon.cc
#include "native-addon.h"
Napi::FunctionReference NativeAddon::constructor;
Napi::Object NativeAddon::Init(Napi::Env env, Napi::Object exports) {
Napi::HandleScope scope(env);
Napi::Function func = DefineClass(env, "NativeAddon", {
InstanceMethod("callInNativeFunction", &NativeAddon::CallInNativeFunction)
});
constructor = Napi::Persistent(func);
constructor.SuppressDestruct();
exports.Set("NativeAddon", func);
return exports;
}
NativeAddon::NativeAddon(const Napi::CallbackInfo& info)
: Napi::ObjectWrap<NativeAddon>(info) {
js = Napi::Persistent(info[0].As<Napi::Function>());
}
Napi::Value NativeAddon::CallInNativeFunction(const Napi::CallbackInfo& info) {
Napi::Env env = info.Env();
// Call your native C / C++ method
// ...
// Call in JS
js.Call({});
return env.Undefined();
}
I hope that he example is helpful to you in general when you want store JavaScript Object or Function you need to use Napi::ObjectReferenceand [Napi::FunctionReference`](https://github.com/nodejs/node-addon-api/blob/master/doc/function_reference.md).
Here I post the complete example:
ref-example.zip
@felipezacani Any news about this issue? Do you need some help?
@felipezacani Any news about this issue? Do you need some help?
Thanks!
Yes, your example was very helpful, it gave me a good insight on improving my code with OO. The real "trick" I missed was actually using the function reference's own ENV to call itself (I think that's missing in your js.Call({})).
Hi @felipezacani,
your environment (this) is stored by Napi::FunctionReference and when you call the method Napi::FunctionReference::Call using only empty initialiser list the call happen using the stored environment.
If you need to specify a different this object you can use the other methods of Napi::FunctionReference:
Napi::Value Napi::FunctionReference::Call(napi_value recv, const std::initializer_list<napi_value>& args) const;
Napi::Value Napi::FunctionReference::Call(napi_value recv, const std::vector<napi_value>& args) const;
Napi::Value Napi::FunctionReference::Call(napi_value recv, size_t argc, const napi_value* args) const;
The napi_value recv represents this object passed to the referenced function when it's called.
The
napi_value recvrepresentsthisobject passed to the referenced function when it's called.
Good to know. I was using ref->env as the first parameter for every call, because I saw it being used like that in another issue.
So, lets say you just write a script initializing an addon and nothing else, the stored env will always be the global environment, right?
In my case, I initialize the addon along with all global things in my server (and I provide it with a global callback function).
So, lets say you just write a script initializing an addon and nothing else, the stored env will always be the global environment, right?
Yes you're right.
Thank you @NickNaso , you've been really helpful. I will close this issue and I'm planning to write an article on this as soon as possible. I'll share it when its done :)
馃憤 Yes I hope to read your article very soon.
Most helpful comment
HI @felipezacani,
you can use
Napi::FuntionReferenceto store the JavaScript function. I report a little example below:index.js
native-addon.h
native-addon.cc
I hope that he example is helpful to you in general when you want store JavaScript Object or Function you need to use
Napi::ObjectReferenceand [Napi::FunctionReference`](https://github.com/nodejs/node-addon-api/blob/master/doc/function_reference.md).Here I post the complete example:
ref-example.zip