4

我试图从我函数的另一个点调用 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 然后调用触发器),我得到:

#
# 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, {});
    }
}

但同样的错误:'(

4

2 回答 2

3

不确定问题的作者是否仍然需要答案。反正。

继续先前关于将本地处理程序转换为持久的答案。Node.js C++ 插件文档页面上有一些示例:
https

://nodejs.org/api/addons.html#addons_function_factory 对于持久对象,他们使用静态构造函数方法作为Persistent<Function>。当模块被初始化时,构造函数可以通过像这样的Reset方法初始化(实际上我没有在 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 handle cast,如下所示:

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

请注意,您不能使用Handle指针,因为它的::New方法不适合此类参数。

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

于 2015-07-20T22:56:56.443 回答
0

我认为您应该在将它们存储Local<T>到. 如果你不这样做,来自 v8 的 GC 可能会随时收集这些函数。Persistent<T>events

Handle<Function> args0 = Handle<Function>::Cast(args[0]);
Persistent<Function> pfn(args0);
callback cb = callback(isolate, pfn); // use Persistent<T> instead of Local<T>
于 2015-02-23T16:23:34.393 回答