Issue between mongodb and EventEmitter

I'm having a weird issue between node-mongodb-native and EventEmitter.

I've reduced the problem to this code:

var mongodb = require( 'mongodb' ),
    Server = mongodb.Server,
    Db = mongodb.Db,
    events = require( 'events' ).EventEmitter.prototype;

// Create a mongo client object
var client = new Db( 'tartempion',
    new Server(
        '127.0.0.1',
        27017
    )
);

// Open the connection
client.open( function( err, db ) {
    if ( err ) throw err;
    database = db;
    console.log( 'Database driver loaded.' );
    events.emit( 'hi' );
});

// If I comment this out, I don't get the error anymore
// and the "Database driver loaded." log is displayed.
events.on( 'hi', function() {
    console.log( 'hey man' );
});

And I'm getting this error:

net.js:140
    // Uncomment the following lines after libuv backend is stable and API
      ^
RangeError: Maximum call stack size exceeded

I thought this may be related to events in a callback, but this code works:

events.on( 'hi', function() {
    console.log( 'hey man' );
});

f( function() {
    events.emit( 'hi' );
});

function f( callback ) {
    callback();
}

So... I'm not seeing where the issue is.

Just FYI, I cross posted this on the node-mongodb-native issue queue.

If you say:

events = require( 'events' ).EventEmitter.prototype;
event.on('foo');

You are asking for trouble because then EVERY event object will get this binding (because you are writing it to the base prototype for all events)...

It's much better (as Jonathon says) to instantiate a new object upon which to bind your events...

sharedEventEmitter.js

var events = require('events');
var eventEmitter = new events.EventEmitter();
module.exports = eventEmitter;

Now from the rest of your project - you can treat this like a singleton - one object that will emit events to anything listening - each time you require('sharedEventEmitter') you get the same instance back (it's a singleton):

a.js

var sharedEvents = require('./sharedEventEmitter');
sharedEvents.on('foo', function(st){
  console.log(st);
})

b.js

var sharedEvents = require('./sharedEventEmitter');
sharedEvents.emit('hello from another file');

You'll have to define events as an instance of EventEmitter rather than just a reference to the EventEmitter.prototype object:

var ...,
    EventEmitter = require('events').EventEmitter,
    events = new EventEmitter;

Or as an object that inherits from EventEmitter.prototype:

var ...,
    events = Object.create(require('events').EventEmitter.prototype);

You only get one EventEmitter.prototype per run of node.exe (since the result of require('events') is cached), so using it as an instance may modify every actual instances used throughout the core Node APIs and by 3rd-party modules like mongodb.


As Brandon suggested, if you need to access the instance in 2 modules, define it in a 3rd module:

// emitter.js
var EventEmitter = require('events').EventEmitter;
module.exports = new EventEmitter;
var ...,
    events = require('./emitter');