Events
Learn about Events and the EventEmitter class in Node.js.
We'll cover the following
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 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.
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 itmyEmitter
in line 3. - Since the
on
method needs a function to attach with an event, we define a function namedsomeFunction
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.
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.
const EventEmitter = require('events');const myEmitter = new EventEmitter();handleError = function (errorCode) {// do something about the errorconsole.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 passing9
as an argument to theemit
method in line 12. This is then passed to ourhandleError
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.
- The
order
event will be fired when we place an order for somefood
. It should outputOrder placed for food
, where food will be the variable passed to the emitter. - The
doorbell
event will be fired when ourfood
is at the door. It should outputRING RING!
. - The
payment
event will be fired once we pay for ourfood
at the door. It should outputEnjoy your food
, wherefood
will be the variable passed to the emitter.
- The
- 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.
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.