NodeJS wait for callback to finish on event emit

I have and application written in NodeJS with Express and am attempting to use EventEmitter to create a kind of plugin architecture with plugins hooking into the main code by listening to emitted events.

My problem comes when a plugin function makes an async request (to get data from mongo in this case) this causes the plugin code to finish and return control back to the original emitter which will then complete execution, before the async request in the plugin code finishes.

E.g:

Main App:

// We want to modify the request object in the plugin  
self.emit('plugin-listener', request);

Plugin:

// Plugin function listening to 'plugin-listener', 'request' is an arg
console.log(request);

// Call to DB (async)
this.getFromMongo(some_data, function(response){
    // this may not get called until the plugin function has finished!
}

My reason for avoiding a callback function back to the main code from the 'getFromMongo' function is that there may be 0 or many plugins listening to the event. Ideally I want some way to wait for the DB stuff to finish before returning control to the main app

Many Thanks

Using the EventEmitter for plugin/middleware management is not ideal, because you cannot ensure that the listeners are executed sequentially, if they have asynchroneous code. This especially is a problem when these listeners interact with each other or the same data.

That's why i.e. connect/express middleware functions are stored in an array and executed one after the other, instead of using an EventEmitter; They each need to call a next(); function when they are done doing their task.

You can't mix asynchronous calls with synchronous behavior. If you're going to stick with event emitter (which may not be ideal for you as Klovadis pointed out), you'll need to have your plugin emit an event that triggers a function in the main app which contains the code that you want to 'wait' to execute. You would also have to in turn keep track of all the plugin calls you made that you are waiting for event calls for so that your main code doesn't run until all the plugin calls have finished their MongoDB callbacks.

var callList = ['pluginArgs1', 'pluginArgs2', 'pluginArgs3'];
for (var i = 0; i < callList.length; i++){
  self.emit('plugin-listener', callList[i], i);
}

self.on('plugin-callback', function(i){
  callList.splice(i, 1);
  if (callList.length < 1){
    //we're done, do something
  }
});

Haven't tried it myself but you could use a property in the event's data object as an array of functions to execute by the code that emitted the event :

Listeners

foo.on('your-event', function(data) {
  console.log(data);
  // Then add the asynchronous code to a callbacks array
  // in the event data object
  data.callbacks.push(function(next) {
    getFromMongo(some_data, function(err, result) { next(err) }
  }
});

Emitter

self.emit('your-event', data);
// listeners have modified data object,
// some might have added callback to data.callbacks
// (suppose you use async)
async.series(data.callbacks);

Had the same kind of decision to make about some events that I sometime need to wait for before returning the response to the client and sometimes not (when not in an HTTP request context).

The easiest way for me was to add a callback as the last argument of the event.

Stuff.emit('do_some_stuff', data, data2, callback);

In the event check if there is a callback:

Stuff.on('do_some_stuff', function(data, data2, callback) {
  // stuff to do
  // ...
  if (typeof callback === "function") return callback(err, result);
});

I know that mixing event and callbacks can be messy but that work fine for what I need. The other solution I see is the one proposed by @redben: add an emit function at the end of the event. The problem when in a HTTP context is that you need unique keys so your events don't mess up if they do different stuff per user.