使用node.js从C++中调用JavaScript

24

有没有一种方法可以通过node.js从C++中调用JS函数(作为回调或类似于此的方式)? 如果有,如何实现? 我正在网上搜索,但没有找到任何有用的资源。

提前感谢。


1
https://dev59.com/8mkw5IYBdhLWcg3wzdzZ - Santosh Dhanawade
2
https://nodejs.org/api/addons.html#addons_callbacks - pdeschain
19
这些链接恰恰与OP所要求的相反。需要翻译的是如何从C++调用JS。 - SpacemanScott
2个回答

6

一种从本地插件中实现的方法是使用提供的函数作为回调函数,例如假设您在本地环境(本地插件)中声明了一个名为 setPrintFunction() 的函数:

(例如,将其命名为 main.cc)

#include <node.h>
#include <string>

v8::Persistent<v8::Function> fn;

// Call this at any time, but after the capture!
void printToNode(std::string msg) {
  auto isolate = fn->GetIsolate();
  // This part is the one that transforms your std::string to a javascript
  // string, and passes it as the first argument:
  const unsigned argc = 1;
  auto argv[argc] = {
      v8::String::NewFromUtf8(isolate,
                          msg.c_str(),
                          v8::NewStringType::kNormal).ToLocalChecked()
  };
  cb->Call(context, Null(isolate), argc, argv).ToLocalChecked();
}

// This is your native function that captures the reference
void setPrintFunction(const v8::FunctionCallbackInfo<Value>& args) {
  auto isolate = args.GetIsolate();
  auto context = isolate->GetCurrentContext();
  auto cb = v8::Local<v8::Function>::Cast(args[0]);
  fn = v8::Persistent<v8::Function>::New(cb);
}

// This part exports the function
void Init(v8::Local<v8::Object> exports, v8::Local<v8::Object> module) {
  NODE_SET_METHOD(module, "exports", setPrintFunction);
}

NODE_MODULE(NODE_GYP_MODULE_NAME, Init)

然后,只需导入您的插件并像这样使用它:
(例如,将其称为 index.js )
const { setPrintFunction } = require('<your path to .node file>');

function printNodeMsg(msg) {
  console.log('<msg>: ' + msg);
}

setPrintFunction(printNodeMsg);

你所做的基本上是获取对 v8::Function 的引用(即javascript函数,但在本机环境中),然后调用它并将"Hello World!"作为第一个(唯一)参数传递。

更多相关信息请参阅: https://nodejs.org/api/addons.html


你能否添加一个C++使用该解决方案的示例?在这种情况下,将一个std::string传递给C++函数,该函数将被传递到其JavaScript对应部分。 - plasmacel
我认为我明白你想要什么:例如,可以编写一个函数来捕获对另一个函数的引用,然后在需要时,在本地部分创建一个调用它的函数。这可能是一个可行的解决方案吗? - Sigma Octantis
当我提出这个问题时,我想知道以下内容:假设我有一个JS函数printNodeMsg(msg),我想从C++中调用它并将msg参数传递给它。插件不是问题,但我希望能够传递参数,而不仅仅是调用函数。因此,调用C++函数void printNodeMsg(const std::string& msg)将在JS站点上调用prontNodeMsg(msg),传递指定的字符串数据。 - plasmacel
2
这个解决方案难道不是与 OP 的问题相反吗? - barath
@barath,OP问如何在使用node的C++上下文中调用由JavaScript创建的函数。据我所知,OP希望有一个C/C++过程,可以提供JS函数,以便可以从JS上下文中制作它,但在C++程序的过程中稍后使用。 - Sigma Octantis

-3
当然可以。例如,如果您想在C++中编写一个简单的阶乘函数,您可以这样做:
#include <node.h>

using namespace v8;

int factorial(int n) {
    if (n == 0) return 1;
    else return n * factorial(n - 1);
}

void Factorial(const FunctionCallbackInfo<Value>& args) {
    Isolate* isolate = Isolate::GetCurrent();
    HandleScope scope(isolate);

    if (args.Length() != 2) {
        isolate->ThrowException(Exception::TypeError(String::NewFromUtf8(isolate, "Wrong number of arguments")));
    } else {
        if (!(args[0]->IsNumber() && args[1]->IsFunction())) {
            isolate->ThrowException(Exception::TypeError(String::NewFromUtf8(isolate, "Wrong arguments type")));
        } else {
            int result = factorial(args[0]->Int32Value());

            Local<Function> callbackFunction = Local<Function>::Cast(args[1]);
            const unsigned argc = 1;
            Local<Value> argv[argc] = { Number::New(isolate, result) };

            callbackFunction->Call(isolate->GetCurrentContext()->Global(), argc, argv);
        }
    }
}

void Init(Handle<Object> exports) {
    NODE_SET_METHOD(exports, "factorial", Factorial);
}

NODE_MODULE(Factorial, Init)

在你的 JavaScript 文件中,像这样调用它:
var factorialAddon = require('./addons/Factorial');
factorialAddon.factorial(5, function (result) {
    console.log(result);
});

6
他的意思是相反的...从C++调用JS。 - delijati

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接