I am Hack Sparrow
Captain of the Internets.

Node.js EventEmitter Tutorial

Heard about Node.js' EventEmitter class? Maybe you know that most of the built-in Node libraries use it? Maybe you were always curious about EventEmitter, but had no one to explain it to you?

In this tutorial, I will give you a guided demo of the great EventEmitter class.

You must be familiar with various Node library events like "on data", "on end", "on error", etc. The event mechanism work so flawlessly and perfectly, doesn't it. All courtesy of EventEmitter. All the event-based Node.js libraries are EventEmitters! In OOP lingo, you might say those Node libraries extend EventEmitter.

The power of EventEmitter need not be limited to the built-in Node libraries anymore - now it can be yours too!

The best way to show what EventEmitter is capable is through an example. Take a look at this:

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

radium.on('radiation', function(ray) {
    console.log(ray);
});

setInterval(function() {
    radium.emit('radiation', 'GAMMA');
}, 1000);

Notice how easy it is to create custom events, add event listeners, emit events, and pass messages via events. All of those are possible because of the EventEmitter magic. EventEmitter is what makes it possible to write amazing libraries for Node.js.

The above example was based on an instance of EventEmitter; how do we create classes that extend EventEmitter? Node.js has a library named util, which has a method named inherits, which makes it possible to easily extend any class using any other class:

var util = require('util');
util.inherits(MyClass, SuperClass);

Using our new-found knowledge of util.inherits(), we will create a Node.js module that extends EventEmitter. Pay good attention to the comments in the code.

File: radio.js

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

// @station - an object with `freq` and `name` properties
var Radio = function(station) {

    // we need to store the reference of `this` to `self`, so that we can use the current context in the setTimeout (or any callback) functions
    // using `this` in the setTimeout functions will refer to those funtions, not the Radio class
    var self = this;
    
    // emit 'open' event instantly
    setTimeout(function() {
        self.emit('open', station);
    }, 0);
    
    // emit 'close' event after 5 secs
    setTimeout(function() {
        self.emit('close', station);
    }, 5000);
    
    // EventEmitters inherit a single event listener, see it in action
    this.on('newListener', function(listener) {
        console.log('Event Listener: ' + listener);
    });
    
};

// extend the EventEmitter class using our Radio class
util.inherits(Radio, EventEmitter);

// we specify that this module is a refrence to the Radio class
module.exports = Radio;

There we have created our Node module extending EventEmitter. Now let's see how we can use it in an example script.

File: example.js

var Radio = require('./radio.js');

// a station object
var station = {
    freq: '80.16',
    name: 'Rock N Roll Radio',
};
// create an instance of the Radio class
var radio = new Radio(station);

// add an 'open' event listener
radio.on('open', function(station) {
    console.log('"%s" FM %s OPENED', station.name, station.freq);
    console.log('♬ ♫♬');
});

// add a 'close' event listener
radio.on('close', function(station) {
    console.log('"%s" FM %s CLOSED', station.name, station.freq);
});

Run test.js and get ready to behold the magic of EventEmitter.

If, for some reason you don't feel like using the util module and doing util.inherits(), you can extend a class (let's say Apple) this way:

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

EventEmitter will help you write impressive event-based Node modules. Also your knowledge of EventEmitter will greatly affect your efficiency as a Node.js developer, so make sure to read more about it and learn how it works inside out. If you don't know EventEmitter, you don't know Node.js yet!

10 Responses to “Node.js EventEmitter Tutorial”

  1. Marko says:

    What if you want something just more advanced than just console.log inside .on call? E.g. have local variable which want to increment. In my code, I can’t use literally ANYTHING within .on function’s scope.

  2. Niranjan says:

    Thanks Captain,

    That is a very good explanation for the beginners.

    Thanks
    Niranjan

  3. Captain says:

    Thanks Niranjan, all the best!

  4. picharnan says:

    Thank Niranjan, this is the best concept about event driven.

  5. Osqui says:

    Hello Captain.
    First of all, many thanks for your so good tutorials, and I wish you book is a big success!!

    Secondly, I have a question I can’t get off my mind. I’d very glad if you could answer it. I’ve searched around all Internet but I don’t understand so technical words…

    It’s about the famous “event loop”…Well, strictly speaking, about these line inside Radio constructor:

    // emit ‘open’ event instantly
    setTimeout(function() {
    self.emit(‘open’, station);
    }, 0);

    WHY WRITING A SIMPLE LINE LIKE this.emit(‘open’, station) INSTEAD OF PREVIOUS CODE DOESN’T WORK??

    Please, please, please. I suspect I’m missing some important concepts I cannot catch.

    Thanks!!!!

    P.D: People say that it’s better to use setImmediate(f) rather than setTimeout(f,0) but this isn’t relevant for the question

  6. Captain says:

    Hi Osqui, thanks for the good wishes!

    When you do self.emit('open', station) in the constructor, the event is emitted before an event listener for the open event is created. The event is emitted even before an instance of Radio created, so we’ll never be be able to listen for the open event.

    Using setImmediate to envoke the emitter will work because, tasks under setImmediate are executed at the end of the current loop, which will include the setting up of the event listener for the open event.

    This post was create before setImmediate was introduced in Node. I still would have used setTimeout to keep it beginner-friendly. You might also want to check out process.nextTick().

  7. Osqui says:

    Ooooh, thanks a lot!!
    I understand finally!! Clear and clever words, it was what I wanted.
    Thanks, thanks!!

  8. Khalil says:

    Very goog tutorial, thanks a lot !

  9. Jan Rathmer says:

    Thank you for this good tut! Nice work, gave me a short introduction to emitting events from submodules.

  10. Christian Gabriel says:

    Thank you for this good explanation.

Make a Comment