Search code examples
javascriptc++node.jsnode.js-addon

Using NAN, how do I call Javascript from a C++ function that's not a NAN_METHOD?


I'm making a C++ native add-on using NAN. My AddOn.cc file contains a NAN method Update() that gets called from Javascript. Update() then calls a C++ dependency library, which in turn calls back into my NON-NAN function in Addon.cc StatusHandler(). This in turn calls the Javascript callback.

Before Update() is ever called, the Javascript code calls Startup() and passed a function to be used as the callback from within StatusHandler().

Here's the relevant code from my ADDON.CC file:

// Javascript status delegate
v8::Local<v8::Function> jsStatusDelegate;

NAN_METHOD(Startup) {
    // Set Javascript status delegate
    jsStatusDelegate = v8::Local<v8::Function>::Cast(info[0]);
}

// Update method called from Javascript
NAN_METHOD(Update) {
    // Call method that will call back to StatusHandler
    myLibrary->Update();
}

// Status delegate called back from dependency library
void StatusHandler(LibStatus &status) {
    // Create callback parameters
    const int argc = 1;
    v8::Local<v8::Value> args[argc];
    args[0] = Nan::New("All Good.").ToLocalChecked();

    TRACE("=========== Calling Javascript Delegate");
    Nan::Callback callbackFunc(jsStatusDelegate);
    v8::Local<v8::Value> jsReturnValue = callbackFunc.Call(argc, args);
}

Here's the relevant code from my test script:

var addon = require('bindings')('addon');

addon.Startup(StatusDelegate);
addon.Update();

function StatusDelegate(status) {
    console.log("******** Javascript StatusDelegate ********");
    console.log(status);
}

Everything compiles and runs with no errors on both sides. I see the TRACE from the C++ statement, but don't see the prints from StatusDelegate().

What have I done incorrectly? Is StatusDelegate() actually getting called? If so, why don't I see the log statements?


Solution

  • Here are the relevant changes which made it work.

    // Javascript status delegate
    Nan::Callback jsStatusDelegate;
    
    NAN_METHOD(Startup) {
        // Set Javascript status delegate
        jsStatusDelegate.Reset(info[0].As<v8::Function>());
    }
    
    // Status delegate called back from dependency library
    void StatusHandler(LibStatus &status) {
        // ...same code...
        TRACE("=========== Calling Javascript Delegate");
    
        // New code
        v8::Local<v8::Value> jsReturnValue = jsStatusDelegate.Call(argc, args);
    }
    

    It's a subtle change and I'm not entirely sure why this way works but the other doesn't. It would appear "Nan::Callback" is retained in some way that "v8::Local" isn't.