Reputation: 55
I need some help to solve my problem. Basically, I want to "call" javascript function from C++ addon, I've googled about it and found something like this.
Here is my .js file
const myaddon = process.binding('myaddon');
function Foo() {
console.log("wooo");
}
myaddon.getfoo(Foo);
myaddon.callfoo(); // just to test if C++ Call js function work
Here is my .cpp
Local<Function> pfOnScriptInit;
Local<Object> globel;
void test(const FunctionCallbackInfo<Value>& args)
{
pfOnScriptInit = Local<Function>::Cast(args[0]);
}
void call(const FunctionCallbackInfo<Value>& args)
{
pfOnScriptInit->Call(globel, 0, nullptr);
}
void initAll(Local<Object> target, Local<Value> unused, Local<Context> context, void* priv)
{
node::Environment* env = node::Environment::GetCurrent(context);
globel = env->context()->Global();
env->SetMethod(target, "getfoo", test);
env->SetMethod(target, "callfoo", call);
}
NODE_MODULE_CONTEXT_AWARE_BUILTIN(fivemp, node::fivemp::initAll)
I got this error when calling myaddon.callfoo();
function:
TypeError: Illegal Invocation
Upvotes: 3
Views: 1934
Reputation: 1057
This question is kinda old, but it's a common question, which has been asked a couple times. These answers don't have a proper answer in my opinion. Hence, here I go!
Before I answer your question, let me say that you should use Native Abstractions for Node.js to write a Node.js addon. This will make your addon portable across Node.js versions.
Also, you should take a look at the official addon documentation here, and to the repo with Nan examples.
That said, your code has a big and common mistake: you are confusingly using a local object as persistent. In other words, declaring a Local<Function>
out of a function scope is plain wrong. These two cannot be declared anywhere but in function scope:
Local<Function> pfOnScriptInit;
Local<Object> globel;
And of course, you cannot assign a Local<Function>
like this:
pfOnScriptInit = Local<Function>::Cast(args[0]);
This local object is going to be reclaimed by v8's garbage collector - it won't exist anymore. So, instead you need to use a persistent
type. Here is an example, written using Nan, which might show you how it's done:
#include <nan.h>
static Nan::CopyablePersistentTraits<v8::Function>::CopyablePersistent _cb;
static void SetCallback(const Nan::FunctionCallbackInfo<v8::Value>& info) {
_cb = Nan::Persistent<v8::Function>(info[0].As<v8::Function>());
}
static void RunCallback(const Nan::FunctionCallbackInfo<v8::Value>& info) {
Nan::MakeCallback(Nan::GetCurrentContext()->Global(), Nan::New(_cb), 0, 0);
_cb.Reset();
}
void RunThisCallback(const Nan::FunctionCallbackInfo<v8::Value>& info) {
v8::Local<v8::Function> cb = info[0].As<v8::Function>();
Nan::MakeCallback(Nan::GetCurrentContext()->Global(), cb, 0, 0);
}
static void Init(v8::Local<v8::Object> exports, v8::Local<v8::Object> module) {
Nan::SetMethod(exports, "setCallback", SetCallback);
Nan::SetMethod(exports, "call", RunCallback);
Nan::SetMethod(exports, "callThis", RunThisCallback);
}
NODE_MODULE(addon, Init)
And here's the JS side:
var addon = require('bindings')('addon');
function foo() {
console.log("woohoo!");
}
addon.setCallback(foo);
addon.call();
addon.callThis(() => console.log("this too!"));
For more information about v8's local vs persistent, you should take a look at v8's documentation. There is a also a good book about Node.js addons by Scott Frees, here https://scottfrees.com/ebooks/nodecpp/.
Upvotes: 5