Events

Learn about Events and the EventEmitter class in Node.js.

Event-driven architecture

Most of Node.js is built around an asynchronous, event-driven architecture. Core APIs, such as the fs module or the net, module use events to communicate with the program. Once the fs module is ready to provide data to be read, it emitscreates a signal for an event. Whenever a new connection is established, the net.Server object emits an event.

To handle events, Node.js uses the events module. It has a class named EventEmitter, and all objects that emit events belong to this class. What should the program do once an event is emitted? For this, the eventEmitter.on() function is used. This allows for one or more functions to be attached to a specific event. These attached functions are also called listeners, as they listen for events to be emitted. Furthermore, listener functions are called synchronously once the object emits a specific event. This makes sure that the sequence of events is preserved and no race conditions or logic errors arise.

Let’s look at the examples below to see how this works.

In the example above, the doorbell is your EventEmitter. When the food delivery person arrives at your door, they can press the doorbell, which then emits a sound. Since you were waiting for your food, you were actively listening for the bell. You are the listener and, upon hearing the doorbell, you proceed to walk towards the door to get your food.

Let’s see how this works in Node.js.

Press + to interact
const EventEmitter = require('events');
const myEmitter = new EventEmitter();
someFunction = function (){
console.log('Something has happened!');
}
myEmitter.on('Some event', someFunction);
myEmitter.emit('Some event');
  • We import the events module in line 1.
  • Using the new keyword, we create an object and name it myEmitter in line 3.
  • Since the on method needs a function to attach with an event, we define a function named someFunction on line 5.
  • We define the on method on line 8 and pass it the name of the event, Some event, and the function to call when this event is emitted, someFunction.
  • Finally, we emit our event, Some event, on line 10.

once

Listener functions registered using the on method are called each time their specific event is emitted. What if we just wanted to call the function once? For that, we use the once method. Listeners registered using the once method are only called once. Let’s look at an example.

Press + to interact
const EventEmitter = require('events');
const myEmitter = new EventEmitter();
let n = 0;
someFunction = function (){
n++
console.log(`Value of n is: ${n}`);
}
myEmitter.once('event', someFunction);
myEmitter.emit('event');
myEmitter.emit('event');
myEmitter.emit('event');

As you can see above, we emit the event three times but we only get the output once. Try changing the once method to on and see what happens.

Handling errors

Errors can be especially troublesome when they occur in an EventEmitter. If we do not have a listener registered to handle an error event, a stack trace will be printed and the process will exit. Therefore, it is good coding practice to have a listener for an error event. Let’s look at how that may be done.

Press + to interact
const EventEmitter = require('events');
const myEmitter = new EventEmitter();
handleError = function (errorCode) {
// do something about the error
console.error('Woah, there was an error! \nError code:', errorCode);
}
myEmitter.on('error', handleError);
myEmitter.emit('error', 9);

You can also pass arguments to your listener function with the emit method. We are passing 9 as an argument to the emit method in line 12. This is then passed to our handleError function as input.

While this may not seem much different from our previous code example, it should be noted that the error events are special and need to be handled. Try to emit an error event in the first code example and see what happens.

Coding challenge

In our illustration, we described a scenario where not having a doorbell can be a problem, especially since we are hungry and waiting for food. Let’s see if we can remedy this.

  • There are three events that we need to take care of.
    1. The order event will be fired when we place an order for some food. It should output Order placed for food, where food will be the variable passed to the emitter.
    2. The doorbell event will be fired when our food is at the door. It should output RING RING!.
    3. The payment event will be fired once we pay for our food at the door. It should output Enjoy your food, where food will be the variable passed to the emitter.
  • All the outputs should be done using console.log.
  • The placeOrder function on line 5 describes the flow of how the events might be emitted. It is only there to help you. You do not have to uncomment it.
Press + to interact
const EventEmitter = require("events");
const myEmitter = new EventEmitter();
// placeOrder = function (food) {
// myEmitter.emit("order", food);
// myEmitter.emit("doorbell");
// myEmitter.emit("payment", food);
// };
// Write your code below

Get hands-on with 1300+ tech skills courses.