Search code examples
javascriptc++v8

How to call a Javascript function from V8 in C++


To run a simple Javascript program using v8 I go about it as follows:

// Create a string containing the JavaScript source code.
v8::Local<v8::String> source = v8::String::NewFromUtf8(isolate, "'Hello' + ', from Javascript!'", v8::NewStringType::kNormal).ToLocalChecked();

// Compile the source code.
v8::Local<v8::Script> script = v8::Script::Compile(context, source).ToLocalChecked();

// Run the script to get the result.
v8::Local<v8::Value> result = script->Run(context).ToLocalChecked();

How can I go about calling a Javascript function in a /path/to/my_js_functions.js file?

function myJsFunction(stringParam) {
  return stringParam   // The function returns a stringParam from the parameter
}  

Thank you all in advance.


Solution

  • First you have to get your hands on the function object. Assuming it's in the global scope (== on the global object), you can access it like this:

    v8::Local<v8::String> name = v8::String::NewFromUtf8(
        isolate, "myJsFunction", v8::NewStringType::kInternalized).ToLocalChecked();
    v8::Local<v8::Value> obj =
        context->Global()->Get(context.local(), name).ToLocalChecked();
    if (!obj->IsFunction()) {
      /* someone overwrote it, handle error */
    }
    v8::Local<v8::Function> my_function = v8::Local<v8::Function>::Cast(obj);
    

    Note that every time you get a MaybeLocal, the result could be empty, which happens when an exception was thrown. If you can't guarantee that that won't happen, then you shouldn't just use .ToLocalChecked() (which will crash when the MaybeLocal is empty), but instead properly check for and handle the error case.

    Once you have a function, you can prepare arguments for it and call it:

    v8::Local<v8::Value> receiver = ...;
    int argc = ...;
    v8::Local<v8::Value> args[argc] = ...;
    v8::MaybeLocal<v8::Value> result = my_function->Call(context.local(), receiver, argc, args);
    

    Again, the result is a MaybeLocal, because functions can throw exceptions (explicitly, or indirectly by calling/doing something that throws). It's up to you to catch any error cases, and otherwise Cast the result to the appropriate type and do something with it.

    (Working with JavaScript through a C++ API is not exactly pleasant. That's largely due to the many conceptual differences between the two languages.)

    For many more examples, have a look at V8's test-api.cc.