Node Event Emitter

Create your own Emitter Module

As with all things, if we fully want to understand any of the concepts presented here, make your own!

We will make our own Emitter which works the same as the Node JS one, all be it on a much simpler level.

Emitter Module – emmiter.js – will let us: 

  • say that an event happened 

  • respond to an event happening

We will create it as a function constructor. In my object I will have one property, an object called events.

Then we add 2 methods to the prototype of this function constructor. These methods will be made available to all objects made from this object.

type is the event I want to respond to. listener is the code that responds to the event. I can have many listeners for the same events. I just keep pushing them into the array for that event. In my code, for a specific event, I will have as many calls to Emitter.prototype.on as types of response I want to have available.

listener – code that responds to an event 

Emitter Module - emmiter.js
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 function Emitter(){
    this.events = {};
 }

 Emitter.prototype.on = function(type, listener){
    // if not exist, create
    this.events[type] = this.events[type] || [];
    this.events[type].push(listener);
 }

Emitter.prototype.emit = function(type){
   if(this.events[type]){
      this.events[type].forEach(function(listener){
         listener();
      });
   }
}

module.exports = Emitter;

Essentially I can now create as many emitters and listeners as I want.

Use the Emitter Module

First we need to require the emitter.js file. The entire Emitter function constructor was exported so that is what we get into our variable. Then we create a new emitter, emtr, from the function constructor.

So now we have an object that is a new emitter and its prototype contains an on and emit methods so they can be used directly.

Using the on method, we create our listeners.

We create 2 listeners for ‘greet‘. We can create as many as we like. I listener is the code that responds to an event. The response can be anything you like.

 

Application file - app.js
~~~~~~~~~~~~~~~~~~~~~~~~~

var Emitter = require('./emitter');

var emtr = new Emitter();

// both of the following will run whenever the greet is emitted
emtr.on('greet', function(){
   console.log('someone said hello');
}); // #1

emtr.on('greet', function(){
   console.log('someone said hello again');
}); // #2

emtr.emit('greet');

Result
someone said hello
someone said hello again

The Node JS Event Emitter

The Node JS Event Emitter also supports the on and emit functions. It works in the same way as the code above, allbeit in a more robust manner.

If you look for on in the Emitter module source code, you will find that it leads directly to another function called addListener which takes 2 arguments, type and listener

If you swap the line 

var Emitter = require('./emitter');

for

var Emitter = require('events');

Everything should work exactly the same.

In Node JS, the event emitter is used extensively. Many other modules are built on top of the events module in order for us to be able to emit, and react to, custom events that we create.

There is a lot to understand about inheritance and how the prototype chain works in Node JS. If you are interested, there are quite a few youtube clips and Udemy courses that work throught these concepts and challenges. Suffice it to say that Node JS has wrapped this complexity into a module calles util.js.  When you require this one, you are able to quite easily add event listeners to any of your objects.

In the Node JS source code, there is a library file called util.js. In there you can see that a function called inherits is exported and lools like this:

exports.inherits = function(ctor, superCtor);

where ctor is your object and superCtor is the object you want your object to inherit from.

Important: before you add any methods at properties to your object, you should FIRST express which objects you want to inherit from.

var EventEmitter = require('events');
var util = require('util');

// function constructor
function Greetr() {
this.greeting = 'Hello world!';
}

// NOTE the order: First inherit
util.inherits(Greetr, EventEmitter);
// essentially what is happening here is that we are setting the EventEmitter prototype to be the Greetr prototypes prototype.

Greetr.prototype.greet = function(data) {
console.log(this.greeting + ': ' + data);
// emit will not be found on this prototype but because we inherited early on from EventEmitter, this prototype function has access to the emit method. Remember, the order of things matters where inheritance and availability are concerned
this.emit('greet', data);
}

var greeter1 = new Greetr();

greeter1.on('greet', function(data) {
console.log('Someone greeted!: ' + data);
});

// the function greet will not be found on the object Greeter but it will be found on its prototype
greeter1.greet('Tony');

// this example also shows how we can pass data to listeners