Вызов существующей функции JavaScript из аддона C++ Node.js - из другого потока

Может быть, я просто не ищу правильные термины, но я застрял..

Мне нужно вызвать функцию JavaScript из C++, очень похоже на то, что можно сделать с помощью простого C API.

Примечание: я не хочу передавать обратный вызов в код C++, но я уже знаю имя вызываемой функции!

Так, например, у меня есть такая функция в JavaScript:

function log_message_callback(context, message) {
  console.log(`${context}: ${message}`);
}

my_napi_module.initialize();   // <-- starts thread that would call log_message_callback

И из C++ я хочу назвать его (кстати, из потока, отличного от основного потока):

#include <napi.h>

void log_message_callback(char const* message) {
  // magic Napi code which would call log_message_callback in JavaScript
} 

void some_thread_fn() {
  log_message_callback("hello world");
}

Я могу сделать это? Как бы я это сделал? И что я должен был искать?!

2 ответа

Функции JavaScript обычно могут вызываться только из основного потока нативного дополнения. Вы можете получить больше информации об этом от

, https://nodejs.org/dist/latest-v11.x/docs/api/n-api.html

Napi_call_function() может использоваться для вызова функции JavaScript из собственного уровня. В документации также есть фрагмент кода для его использования. https://nodejs.org/dist/latest-v11.x/docs/api/n-api.html

Это НЕ ответ - только некоторые результаты исследований.

Похоже, код, который я должен написать, должен выглядеть примерно так - в настоящее время я не знаю, как настроить все для работы..

Большая часть кода взята из этого события.

Эти значения должны быть доступны - похоже, я должен их инициализировать при инициализации модуля.

static v8::Persistent<v8::Context> context_;
static v8::Isolate *isolate_;

Эта функция делает оба поворота log_message_callback() из JavaScript пустошь в v8::Function и зову это. Более сложный подход разделил бы эти шаги:

extern "C" {

void log_message_callback(char const* message) {
  v8::Locker locker(isolate_);
  v8::Isolate::Scope isolate_scope(isolate_);
  v8::HandleScope handle_scope(isolate_);
  auto context = context_.Get(isolate_);
  v8::Context::Scope context_scope(context);

  v8::Persistent<v8::Function> log_message_callback_fn;

  /// this is only needed once - just for demonstration
  {
    auto global = context->Global();
    v8::Local<v8::Value> log_message_callback_def;
    if (!global->Get(
          context, v8Str(isolate_, "log_message_callback")).ToLocal(&log_message_callback_def)) {
      return;
    }

    if (!log_message_callback_def->IsFunction()) {
      return;
    }


    if (log_message_callback_def->IsFunction()) {
      auto on_update_fun = log_message_callback_def.As<v8::Function>();
      log_message_callback_fn.Reset(isolate_, on_update_fun);
    }
  }  

  v8::Local<v8::Value> args[2];
  log_message_callback_fn.Get(isolate_)->Call(context->Global(), 2, args);
}
Другие вопросы по тегам