27

I want to emit events from one file/module/script and listen to them in another file/module/script. How can I share the emitter variable between them without polluting the global namespace?

Thanks!

fancy
  • 48,619
  • 62
  • 153
  • 231

3 Answers3

28

@srquinn is correct, you should use a shared single instance:

eventBus.js:

const EventEmitter = require('events');
const emitter = new EventEmitter();

emitter.on('uncaughtException', function (err) {
    console.error(err);
});

module.exports = emitter;

Usage:

var bus = require('../path/to/eventBus');

// Register event listener
bus.on('eventName', function () {
    console.log('triggered!');
});

// Trigger the event somewhere else
bus.emit('eventName');
Lesh_M
  • 596
  • 8
  • 6
  • 4
    upvoted but doesnt work if i have a file pub.js and another sub.js where i require eventbus.js and try to fire from one and recieve event from another – PirateApp Apr 13 '19 at 16:49
  • That's strange, @PirateApp. It should work. Just make sure you are adding the event handler in sub.js *before* the event is fired in pub.js – ack_inc Sep 25 '21 at 09:39
  • @ack_inc , this is expected behaviour assuming that PirateApp's sub.js and pub.js dont share the same instance of the event Emiter module. sub.js and pub.js must run on the same evenBus instance to call each other. – janithcooray Apr 29 '23 at 03:10
14

You can pass arguments to require calls thusly:

var myModule = require('myModule')(Events)

And then in "myModule"

module.exports = function(Events) {
    // Set up Event listeners here
}

With that said, if you want to share an event emitter, create an emitter object and then pass to your "file/module/script" in a require call.

Update:

Though correct, this is a code smell as you are now tightly coupling the modules together. Instead, consider using a centralized event bus that can be required into each module.

Community
  • 1
  • 1
srquinn
  • 10,134
  • 2
  • 48
  • 54
  • How do you control the flow of those requires? Say 4 files need it. Does the module just expose a variable = new EventEmitter()? And it will be instantiated before anyone does anything with the requires? – fancy May 18 '12 at 21:16
  • 1
    I just implemented the pattern I described and it seems to work quite well. I have a module called `emitters` that exposes an `exports.variable = new EventEmitter()`. Both files `require` this `emitters` module, and can pass events via the `variable`. – fancy May 18 '12 at 21:29
  • You may also consider keeping a Top Level module that creates the Emitter Object and then passing that object to any child modules that need to listen to "Global" events if I dare use that word. – srquinn May 18 '12 at 21:42
  • I assumed the pattern I described would instantiate a new EventEmitter each time I require it but it seems to not behave like that which is really nice. Hopefully I'm not missing something. – fancy May 18 '12 at 21:46
  • 2
    @fancy Node.js caches modules, so the code in them will actually only be run the first time you require that module. – Aaron Dufour Sep 10 '13 at 20:23
12

Why not use the EventEmitter of the global process object?

process.on('customEvent', function(data) {
  ...
});

process.emit('customEvent', data);

Pro: You can disable or completely remove a module (for instance a tracker), without removing all your tracking code within your routes. I'm doing exactly that for node-trackable.

Con: I don't now, but please let me know if you see a catch here ;-)

Byscripts
  • 2,578
  • 2
  • 18
  • 25
Sascha Reuter
  • 355
  • 2
  • 7
  • 1
    eventual / possible conflicts in event names, seems safer to be explicit. – lsl Mar 22 '13 at 04:12
  • 12
    Con: Events will be locked to one process which prevents scaling horizontally via cluster module or other methods. – srquinn Mar 26 '14 at 12:27
  • 1
    @jibsales How would you go about sharing an event emitter between workers in a cluster? Clusters share server ports, but I'm not sure if they can easily share javascript objects – wheresrhys Nov 06 '14 at 10:29
  • @Louis that's going to be a problem on any shared event emitter unless you're careful about naming – wheresrhys Nov 06 '14 at 10:30
  • 1
    @Sascha_Reuter A variant on this might be to assign your own event emitter as a property of process – wheresrhys Nov 06 '14 at 10:33
  • @wheresrhys Using some form of a message bus or wait for the `Domain` module in node's core to mature a bit. – srquinn Nov 07 '14 at 17:12