Calling JavaScript from C++ with node.js

后端 未结 3 1626
一生所求
一生所求 2020-12-29 05:01

Is there a way to call JS functions from C++ through node.js (as callbacks or something like that)? If yes, how? I\'m searching for it on the web, but haven\'t found any hel

相关标签:
3条回答
  • 2020-12-29 05:32

    Of course you can. For example, if you want to write a simple factorial function in C++, you could do something like

    #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)
    

    And in your JavaScript file, call it like this

    var factorialAddon = require('./addons/Factorial');
    factorialAddon.factorial(5, function (result) {
        console.log(result);
    });
    
    0 讨论(0)
  • 2020-12-29 05:37

    One way to do it form a native addon can be using the provided function as a callback, for example let's gonna assume that you have a function named setPrintFunction() declared in your native environment (A native addon):

    (Call this for example 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)
    

    Then, just importing your addon and using it like:

    (Call this for example index.js)

    const { setPrintFunction } = require('<your path to .node file>');
    
    function printNodeMsg(msg) {
      console.log('<msg>: ' + msg);
    }
    
    setPrintFunction(printNodeMsg);
    

    So what you're basically doing is capturing the reference to the v8::Function (Which is the javascript function, but in the native environment) and then invoking it and passing "Hello World!" as the first (and unique) parameter.

    More on the subject: https://nodejs.org/api/addons.html

    0 讨论(0)
  • 2020-12-29 05:40

    the answer is yes, and here is a way to do it :

    I have created a js file called index.js and here is the path to the file

    D:\NodeJS\call_js_from_cpp 
    

    it contains the following code

    console.log("hello");
    

    Now I have a C++ code that executes the following shell command and stores the output in the variable "output" (which is a string):

    node D:\NodeJS\call_js_from_cpp\index.js
    

    Here is the C++ code : (note that in the code, there are double \ in the path so it becomes like this node D:\NodeJS\call_js_from_cpp\index.js)

    #include<iostream>
    #include<fstream>
    #include<string>
    #include<cstdlib>
    #include<sstream>
    
    std::string ssystem (const char *command) {
      char tmpname [L_tmpnam];
      std::tmpnam ( tmpname );
      std::string scommand = command;
      std::string cmd = scommand + " >> " + tmpname;
      std::system(cmd.c_str());
      std::ifstream file(tmpname, std::ios::in );
      std::string result;
      if (file) {
       while (!file.eof()) result.push_back(file.get());
       file.close();
      }
      remove(tmpname);
      return result;
    }
    
    //for cygwin
    
    int main(int argc, char *argv[])
    {
       std::string bash = "node D:\\NodeJS\\call_js_from_cpp\\index.js";
       std::string in;
       std::string s = ssystem(bash.c_str());
       std::istringstream iss(s);
       std::string output;
       while ( std::getline(iss, output) )
        {
          std::cout << output;
        }
    
       return 0;
     }
    
    0 讨论(0)
提交回复
热议问题