EToreo
EToreo

Reputation: 3096

NodeJS Addon calling Javascript callback from inside NAN AsyncWorker::Execute

I would like to call a nodejs callback from within my asynchronous addon function. I have seen the synchronous example (here) and I am using a wonderful asynchronous example (here) as a starting base.

However, when I try to execute a callback that was given to the c++ AsyncWorker child class, I get a Segmentation fault.

Here is my code:

#include <nan.h>
#include <functional>
#include <iostream>
#include <exception>
using namespace Nan;
using namespace v8;
using namespace std;

class ScriptWorker : public AsyncWorker {
  public:
    ScriptWorker(Callback *callback, const std::map<std::string, Callback*>)
    : AsyncWorker(callback), script(script), cbs(cbs) {}

    ~ScriptWorker() {}

    void Execute () {

      // ------------------------
      // Segmentation fault after
      // ------------------------

      Local<Value> argv[] = {
        New<v8::Number>(id)
      };

      // -------------------------
      // Segmentation fault before
      // -------------------------

      cbs["getUser"]->Call(1, argv);
    }

  private:
    std::string script;
    std::map<std::string, Callback*> cbs;
};

NAN_METHOD(Method) {
  Local<Object> array = info[0]->ToObject();
  Callback *callback = new Callback(info[1].As<Function>());

  // Build up callbacks passed in from javascript.
  // Will be a dynamic loop, but for now, hard code the one getUser example.
  std::map<std::string, Callback*> cbs;
  cbs.insert(std::pair<std::string, Callback*>("getUser",
    new Callback(
      array->Get(
        v8::String::NewFromUtf8(v8::Isolate::GetCurrent(), "getUser")
      ).As<Function>()
    )
  ));
  AsyncQueueWorker(new ScriptWorker(callback, cbs));
}

NAN_MODULE_INIT(Init) {
  Nan::Set(target, Nan::New<String>("hello").ToLocalChecked(), Nan::GetFunction(Nan::New<FunctionTemplate>(Method)).ToLocalChecked());
}

NODE_MODULE(hello, Init)

My questions:

  1. Should I not use Nan's AsyncWorker and instead roll my own?
  2. How do I setup the Execute function to call into Javascript?

Upvotes: 4

Views: 4841

Answers (1)

Xavero
Xavero

Reputation: 3389

EDIT:

See this repo:

https://github.com/xavero/node_addon_sample

it has a sample on how to work with callback functions and emitting events from C land.

You should not call v8/Nan functions in your Execute method of ScriptWorker, or you will get segment faults. Override the HandleOKCallback function to use the javascript callback.

To call from the javascript, in your c++ addon:

NAN_MODULE_INIT(Init) {
  Nan::Set(target, Nan::New("myJsFunctionName").ToLocalChecked(),
    Nan::GetFunction(Nan::New<FunctionTemplate>(Method)).ToLocalChecked());
}

NODE_MODULE(anyNameHere, Init)

And in your javascript:

// run "npm install bindings --save" in console first
var addon = require('bindings')('NativeExtension');

addon.myJsFunctionName({ foo: "bar"}, (arg1,arg2) => console.log(`${arg1} - ${arg2}`))

Upvotes: 5

Related Questions