2015-01-25 5 views
4

Я пытаюсь вызвать обратный вызов в V8 из другой точки моей функции. Так что этот кусок кода регистрации обратного вызова:Как вызвать обратный вызов javascript из C++

 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

Line 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); 

EDIT: Я пытался, благодаря Бен 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, {}); 
    } 
} 

Но та же ошибка: '(

+0

Выполняется ли этот код на основном потоке? – mscdex

+0

думаю. Я загружу основной цикл. Во всяком случае, я ничего не сделал для реализации threading – Vinz243

+0

Ошибка указывает, что ваш Isolate не знает о вашем Persistent. Является ли узел инициирующим обратный вызов из нового потока? Узнайте, вызывая v8 :: Isolate :: SetData() в вашей функции addWorldEvent(), затем проверяя, что данные все еще присутствуют в вашей функции trigger(). –

ответ

0

Я думаю, вы должны бросить Local<T> в Persistent<T>, прежде чем хранить их в events. Если вы не хотите, чтобы GC из v8 мог собирать функции в любое время.

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

Я получаю 'ошибка C2664: не могу преобразовать аргумент 1 из 'v8 :: Handle 'to' const v8 :: Persistent > & 'на вашей второй строке – Vinz243

+0

как насчет' Persistent pfn = Persistent :: New (args0); 'Мы можем использовать разные версии, примеры онлайн, похоже, различаются в зависимости от вашей версии v8. –

+0

OK v8.h is https://chromium.googlesource.com/v8/v8/+/4.1.0.14/include/v8.h#690, но я получаю 'can not convert from 'v8 :: Primitive *' to 'v8 :: Object * volatile '' – Vinz243

2

Не уверен, что автор вопроса все еще нуждается в ответе. Так или иначе.

Продолжая предыдущий ответ о преобразовании локальных обработчиков в Persistent. Есть несколько примеров на странице аддонов DOCS Node.js C++:
https://nodejs.org/api/addons.html#addons_function_factory

Для постоянных объектов, которые они используют статический метод конструктора, как Persistent < Функции >. Когда модуль inited конструктор может быть инициализирован 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<Function> f = Local<Function>::New(isoloate,persistentCallback) 

Имейте в виду, вы не можете использовать Берите указатели, потому что его :: Новый метод не подходит для таких аргументов.

BTW.Я понял, что мне не нужно использовать Persistent handler в моем коде для хранения метода обратного вызова в случае, если я уже связал его в контексте JS. Кажется, что в этом случае он надлежащим образом управляется GC. Но нет другого способа разделить vars между вызовами функций C++, например. когда вы храните некоторые защищенные данные внутри вашего модуля.