Executing a callback in Javascript from within a NAN AsyncWorker in a NodeJS Addon

Exploring the idea of calling a Node.js callback from within my asynchronous addon function has been an interesting journey. I found inspiration in both synchronous (here) and asynchronous (here) examples to guide me.

However, encountering a Segmentation fault when trying to execute a callback provided to the C++ AsyncWorker child class was quite a challenge.

This is the essence of 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>());

  // Building up callbacks passed in from JavaScript.
  // Initially focusing on the "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)

I have a couple of questions lingering in my mind:

  1. Is it advisable to forego using Nan's AsyncWorker and craft my own solution instead?
  2. What steps are necessary to configure the Execute function for calling into JavaScript successfully?

Answer №1

UPDATE:

If you're looking to understand how callback functions and event emission work in C, check out this repository:

https://github.com/xavero/node_addon_sample

The sample provided demonstrates the proper approach to working with callback functions and emitting events from the C environment.

Avoid using v8/Nan functions within the Execute method of your ScriptWorker as it can lead to segment faults. Instead, override the HandleOKCallback function to utilize the JavaScript callback.

In your C++ addon file, include the following code snippet:

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

NODE_MODULE(anyNameHere, Init)

Then, in your JavaScript file, implement the following:

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

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

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

What is causing the issue of subdomains not functioning properly in express.js?

Currently, I am conducting some local experiments and have made changes to my hosts file. Here are the entries: 127.0.0.1 example.dev 127.0.0.1 www.example.dev 127.0.0.1 api.example.dev Below is the code I am using: var subdomain = req ...

Caution: npm installation warns about potential issues

After encountering some WARN messages, I attempted to update npm by running npm audit fix However, this resulted in even more WARN messages. When I tried to install all dependencies using npm i I was bombarded with a plethora of WARN messages (see below) ...

Can someone explain why the console.log(items) command seems to be executing twice

Item.find() .then(function (items) { if (items.length === 0) { Item.insertMany(defaultItems) .then(function () { console.log("Successfully Saved"); }) .catch(function (err) { console.l ...

Setting up environments utilizing restify

Having experience with gulp, I am well-versed in setting up a distinct configuration for each environment within a single configuration file. This allows for running gulp dev to initiate the server using the development environment configuration, gulp stag ...

Looking to confirm client-side text in NodeJS?

As I work on constructing a to-do list, one challenge I am encountering is confirming that the correct task has been checked off. While considering using unique IDs for each individual task may seem like a solution, there is still the risk of users manipul ...

Whenever I try to send an email in Node.js, I encounter 404 errors. Additionally,

I have an Angular application with a form that makes AJAX requests. Emailing works fine, but no matter what I set the response to, I get an error for the path '/send'. I assume Node.js expects the path '/send' to render a template or da ...

Is it considered safe to delete the npm-cache folder on a Windows system?

When running npm cache clean -f, I noticed that it was not able to fully clear the npm_cache folder located at C:\Users\jerry\AppData\Roaming\npm-cache. It only cleared some of the files within this directory. The command output d ...

The command you entered could not be found: Expression not recognized

After successfully installing ExpressJS on my OSX using sudo npm install express-generator -g I encountered the following error: -bash: express: command not found During installation, I received this output: /Users/myusername/.node/bin/express -> / ...

Automaton ScheduleTask Feature

I'm struggling to understand how to make this work. My goal is to set up Hubot to automatically call a function at regular intervals in a specific HipChat channel. Currently, I have it working by requiring the user to type "Hubot totalviewers" in the ...

Setting up event triggers once readline is activated

Reading a file line-by-line in NodeJS typically involves calling readline.createInterface, and then attaching event handlers for line and close. It's interesting how the reader seems to start on its own without any explicit trigger. How does it know ...

Why isn't my node.js (express) server receiving the incoming request as expected?

I have a node.js(express) application where I have defined all my routes, controllers, and more. customer.route.js const express = require('express'); const Controller = require('../controllers/customer.controller'); const { customerV ...

Utilizing Mongoose Schema across various endpoints in an Express application

As a newcomer to Node.js, I am using Mongoose and Express for my project. Within the routes/index.js file, I have defined a userDataSchema as follows: var Schema = mongoose.Schema; var userDataSchema = new Schema({ username: String, username_lower: ...

Setting up a project in TypeScript with Angular 2(+) and a Node/Express server is essential for successful

Searching for the optimal approach for a project similar to this: An Angular 2 (4) client coded in TypeScript A Node/Express backend also written in TypeScript Utilizing some shared (TypeScript) models accessible to both client and server code. Is it pr ...

I'm seeking suggestions for a concise regex that can extract alphanumeric IDs followed by optional numbers, all separated by either a hyphen or forward slash

Looking to analyze a group of strings that adhere to specific patterns: {alpha-numeric-id}-{numeric-id} or {alpha-numeric-id}/{numeric-id} The alpha-numeric-id can contain the character -, along with numbers The numeric-id is always a number and may ...

Exploring MongoDB API Pagination

Picture a scenario where a customer has a list of items with a limit of 10. When they need the next set of 10 items, they send a request with a skip of 10 and a limit of 10. However, what if some new items were added to or removed from the collection sinc ...

Access another key within an object

Here's a code snippet from my module: exports.yeah = { hallo: { shine: "was", yum: this.hallo.shine } } In the above code, I'm attempting to reference the shine property in yum: this.hallo.shine However, when I run the script, ...

What are the best practices for integrating Quill with Node.js and MongoDB?

I'm in the process of creating my own blog, and I really want to have a user-friendly interface for updating the content instead of manually editing HTML files each time. My plan is to use the Quill editor to create blog posts (which are saved as del ...

The passport.authenticate function will not run on a specific route

My express project utilizes the Passport-jwt Strategy for authentication. You can find my passport-jwt config in the /config/passport.js directory. var JwtStrategy = require('passport-jwt') .Strategy, ExtractJwt = require('passport-jwt&a ...

Node.js SQLite3 - DB.each() not running the subsequent code block

When running the code snippet below, I am getting the following output: var db = new sqlite3.Database("database.sqlite") console.log("2") db.each("SELECT * FROM gban WHERE id = '"+id+"'", async functi ...

When comparing `xhr.onload = () => {resolve();}` and `xhr.onload = resolve();`, it is important to note the distinction in syntax

function bar(){ return new Promise((resolve,reject)=>{ const xhr = new XMLHttpRequest(); xhr.open(method,url); xhr.onload = ()=>{ resolve(xhr); }; xhr.send(); }) } The code snippet shown above performs as expected Howe ...