如何从C ++调用javascript回调

时间:2015-01-25 14:40:46

标签: c++ node.js v8 embedded-v8 io.js

我正试图从我的功能的另一个角度调用V8中的回调。所以这段代码注册了回调:

        if (args.Length())
        {
            String::Utf8Value event(args[0]->ToString());
            if (event.length())
            {  
                Isolate* isolate = V8Interface::getCurrent()->getIsolate();

                Locker locker(isolate);
                HandleScope scope(isolate);

                callback cb = callback(isolate, Local<Function>::Cast(args[1]));

                 if(!events.count(*event))
                 {
                events[*event] = callbacks({ cb });
                 } 
                 else 
                {
                    events.find(*event)->second.push_back(cb);
                 }
            }
        }

这个人称之为:

 void trigger(std::string event)
    {

        Isolate* isolate = V8Interface::getCurrent()->getIsolate();

        Locker locker(isolate);
        HandleScope scope(isolate);

        if(events.count(event))
        {
            for(callback cb : events.find(event)->second)
            {
                Local<Function> local = Local<Function>::New(isolate, cb);
                local->Call(isolate->GetCurrentContext()->Global(), 0, {});
            }
        }
    }

可以在我的C ++代码中随时随地调用触发器函数。我尝试了一个简单的例子(init v8然后调用trigger),然后我得到:

#
# Fatal error in C:\OgreSDK\Projects\whitedrop\third_party\io.js\deps\v8\src/api.h, line 386
# CHECK(allow_empty_handle || that != 0) failed
#

这是我的主要内容:

Scribe::V8Interface v8Interface = Scribe::V8Interface();
v8Interface.initialize();

for(Whitedrop::WorldEvent* event : Whitedrop::worldEvents)
{
    event->onStart();
}

你可以在这里获得全部资料来源:

https://github.com/whitedrop/whitedrop/tree/feature/v8

第386行是:

/**
   * Create a local handle for the content of another handle.
   * The referee is kept alive by the local handle even when
   * the original handle is destroyed/disposed.
   */
  V8_INLINE static Local<T> New(Isolate* isolate, Handle<T> that); // <<<<<<
  V8_INLINE static Local<T> New(Isolate* isolate,
                                const PersistentBase<T>& that);
编辑:我试过,感谢Ben Noordhuis,就像这样:

Isolate* isolate = V8Interface::getCurrent()->getIsolate();

Locker locker(isolate);
HandleScope scope(isolate);

callback cb;
cb.Reset(isolate, Local<Function>::Cast(args[1]));

致电:

Isolate* isolate = V8Interface::getCurrent()->getIsolate();

Locker locker(isolate);
HandleScope scope(isolate);

if(events.count(event))
{
    for(callback cb : events.find(event)->second)
    {
        Local<Function> local = Local<Function>::New(isolate, cb);
        local->Call(isolate->GetCurrentContext()->Global(), 0, {});
    }
}

但同样的错误:'(

2 个答案:

答案 0 :(得分:2)

不确定问题的作者是否还需要答案。无论如何。

继续以前关于将本地处理程序转换为Persistent的答案。 Node.js C ++插件文档页面上有一些示例:
https://nodejs.org/api/addons.html#addons_function_factory

对于持久对象,他们使用静态构造函数方法作为持久性&lt;函数&gt; 。 当模块被包含时,可以通过重置方法初始化构造函数 像这样(实际上我没有在v8文档中找到它的描述 - http://izs.me/v8-docs/classv8_1_1Persistent.html):

// some where in external class or as global var
static Persistent<Function> persistentCallback;

// when need to init
persistentCallback.Reset(isolate, f_tmpl->GetFunction());

要在需要时调用此方法,您应该使用本地句柄转换,如下所示:

Local<Function> f = Local<Function>::New(isoloate,persistentCallback)

请注意,您无法使用句柄指针,因为其 :: New 方法不适合此类参数。

顺便说一句。我发现我不需要在我的代码中使用Persistent处理程序来存储回调方法,以防我已经将它绑定在JS上下文中。在这种情况下,它似乎由GC妥善管理。但是没有其他方法可以在c ++函数调用之间共享变量,例如。当您在模块中存储一些受保护的数据时。

答案 1 :(得分:0)

我认为您应该将Local<T>投放到Persistent<T>,然后再将其存入events。如果您不这样做,v8中的GC可能会随时收集这些功能。

Handle<Function> args0 = Handle<Function>::Cast(args[0]);
Persistent<Function> pfn(args0);
callback cb = callback(isolate, pfn); // use Persistent<T> instead of Local<T>