最近看了很多的相关文档;但是有有一个地方一直很不解,关于Node调用C++传递回调函数:
官方文档如下:
C++部分:
// addon.cc
#include <node.h>
namespace demo {
using v8::Function;
using v8::FunctionCallbackInfo;
using v8::Isolate;
using v8::Local;
using v8::Null;
using v8::Object;
using v8::String;
using v8::Value;
void RunCallback(const FunctionCallbackInfo<Value>& args) {
Isolate* isolate = args.GetIsolate();
Local<Function> cb = Local<Function>::Cast(args[0]);
const unsigned argc = 1;
Local<Value> argv[argc] = { String::NewFromUtf8(isolate, "hello world") };
cb->Call(Null(isolate), argc, argv);
}
void Init(Local<Object> exports, Local<Object> module) {
NODE_SET_METHOD(module, "exports", RunCallback);
}
NODE_MODULE(NODE_GYP_MODULE_NAME, Init)
} // namespace demo
js部分
// test.js
const addon = require('./build/Release/addon');
addon((msg) => {
console.log(msg);
// Prints: 'hello world'
});
可以看得出来,这个demo中js虽然传递的是function,但是在C++模块是同步的执行的;而且同步执行的话我也调通了,但是实际的场景肯定不是这种需求,而是在C++模块某一个异步的事件监听中收到某一种消息之后才通过js模块传递的回调函数回调给js;
目前已经做好的事情:
封装一个C++的类,并且export,可用js调用此类的实例方法;
.h文件的两个属性:
Isolate *onPlayNoteIsolate;
Local <Function> onPlayNote;
.cpp文件
// 标记为方法1:
void MIDIDeviceHelperBridge::setOnPlayNote(const FunctionCallbackInfo<Value>& args) {
MIDIDeviceHelperBridge *obj = ObjectWrap::Unwrap<MIDIDeviceHelperBridge>(args.Holder());
Local<Function> callback = Local<Function>::Cast(args[1]);
obj->onPlayNote = callback;
obj->onPlayNoteIsolate = args.GetIsolate();
}
// 标记为方法2:
void MIDIDeviceHelperBridge::ReceiveMsg(DWORD Msg, DWORD TimeStamp) {
// 此方法中的this为方法1中的obj
}
我现在的需求是在方法1中获得的js模块的回调函数存储在obj中或者任何在C++模块能访问到的地方,然后在方法2中收到消息之后通过方法1获得的js模块的回调,将消息传递给js模块;
我尝试过在方法1中的obj里存储callback和isolate,然后在方法2中通过this访问callback和isolate,但是收到消息后程序崩溃了,发现isolate没有问题,是callback被释放了,后来也尝试过Local <Function> onPlayNote;
类型换成Persistent <Function> onPlayNote;和Handle<Function> onPlayNote;也都是收到消息后崩溃;
现求问有没有大神做过类似的功能?
========================================================================
经过几个小时后修改部分问题:
1:Persistent <Function> onPlayNote;不存储在类的成员变量中,放到全局,而且必须使用Persistent;
2:发现的其他问题,ReceiveMsg方法我可以在当前类对js公开的方法中调用,并且在js中调用词方法后,js模块的回调也是可以执行的;
3:但实际中ReceiveMsg不是我手动调用的,而是MIDI设备(例如能通过USB连接电脑的电子琴)上的按键触发后通过windows系统的midiapi调用ReceiveMsg方法,此时ReceiveMsg中没有任何js的环境;
========================================================================
已解决
收到的消息存储在当前对象的消息队列,然后通过emit发送到js模块:
C++部分
js部分: