Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Calling a JS function by event emitting

I am not sure how one can call a Node/v8 function within Node's main thread by using event emitting in a separate C++ thread. How is it possible to emit events in a C++ thread?

Before thinking about NanAsyncWorker or uv_queue_work: I don't want to call a C++ function in an Async fashion. I want to do the exact opposite, calling a Javascript function from C++ by emitting events.

like image 623
Sepehr Avatar asked Aug 09 '14 21:08

Sepehr


People also ask

How do you call an event emitter?

EventEmitter() is the constructor function for the EventEmitter object. Since you need to call that constructor with the same this as your new object, you must use either . call() or . apply() with that constructor in order to cause the correct this to be used.

What are event emitters in Javascript?

An event emitter is a pattern that listens to a named event, fires a callback, then emits that event with a value. Sometimes this is referred to as a “pub/sub” model, or listener.

What is emit method in Javascript?

The on or addListener method (basically the subscription method) allows you to choose the event to watch for and the callback to be called. The emit method (the publish method), on the other hand, allows you to "emit" an event, which causes all callbacks registered to the event to 'fire', (get called).

Where do you use event emitter?

Use event emitter if you need to notify the user of a state change. For testing purpose, if you want to make sure a function is called inside a function, emit an event.


1 Answers

You do not need to use uv_queue_work, but part of LibUV's thread library are the uv_async_* methods, which are what you'd ideally have in this case. When you initialize your secondary thread, you'd also do uv_async_init to create a shared async data structure. This function is also called with a callback that will run whenever your other thread sends a message. That callback is where you would call the JS code to trigger your events.

Here's some semi psuedocode as an example:

In your thread init function called from JS with a single callback arg:

void ThreadInit(const v8::Arguments &args){
  // This is just an example, this should be saved somewhere that
  // some_callback will be able to access it.
  v8::Persistent<v8::Function> js_callback = args[0].As<Function>();

  // And save this where you'll be able to call uv_close on it.
  uv_async_t async_data;

  uv_async_init(uv_default_loop(), &async_data, some_callback);

  // initialize the thread and pass it async_data
}

In thread:

async_data.data = (void*) // Some data structure...
uv_async_send(&async_data);

In thread callback:

void some_callback(uv_async_t *async_data){
    // Note that this depending on the data, you could easily get thread-safety issues
    // here, so keep in mind that you should follow standard processes here.
    void* data = async_data->data;

    // Process that data however you need to in order to create a JS value, e.g.
    // Using NanNew because it is more readable than standard V8.
    v8::Local<Number> count = NanNew<Number>(data.count);

    v8::Local<v8::Value> argv[] = {
        count
    };

    js_callback->Call(NanNull(), 1, argv);
}
like image 65
loganfsmyth Avatar answered Oct 21 '22 11:10

loganfsmyth