Event Driven Applications
Event-Driven Programming is a logical pattern that we can choose to confine our programming within to avoid issues of complexity and collision.
Overview
Every time you interact with a webpage through it’s user interface, an event is happening. When you click a button a click event is triggered. When you press a key a keydown event is triggered. These events have associated functions that, when triggered, are executed to make a change to the user interface in some way.
Event-Driven Programming makes use of the following concepts:
- An Event Handler is a callback function that will be called when an event is triggered.
- A Main Loop listens for event triggers and calls the associated event handler for that event.
EventEmitter
Node.js natively provides us with a useful module called EventEmitter that allows us to get started incorporating Event-Driven Programming in our project right away.
We access the EventEmitter class through the events module. Once imported we’ll need to create a new object from the class to start using it.
const EventEmitter = require('events').EventEmitter;
const myEventEmitter = new EventEmitter;
Now we can get started with Event-Driven Programming in Node.
Imagine we’re creating a chat room. We want to alert everyone when a new user joins the chat room. We’ll need an event listener for a userJoined event. First, we’ll write a function that will act as our event listener, then we can use EventEmitters on method to set the listener.
const EventEmitter = require('events').EventEmitter;
const chatRoomEvents = new EventEmitter;
function userJoined(username){
// Assuming we already have a function to alert all users.
alertAllUsers('User ' + username + ' has joined the chat.');
}
// Run the userJoined function when a 'userJoined' event is triggered.
chatRoomEvents.on('userJoined', userJoined);
The next step would be to make sure that our chat room triggers a userJoined event whenever someone logs in so that our event handler is called. EventEmitter has an emit method that we we use to trigger the event. We would want to trigger this event from within a login function inside of our chatroom module.
function login(username){
chatRoomEvents.emit('userJoined', username);
}
Removing Listeners
In the following example, it would be a challenge to remove the listener for the message event from outside of the userJoined function due to the fact that it’s an anonymous function declared within a closure. In this case the only place we would be able to directly reference this method would be in the EventEmitter Object itself. This would be impractical if we ever had more than one listener registered to a single event as we would then have to figure out a way to decipher which of the listeners is our intended target.
const EventEmitter = require('events').EventEmitter;
const chatRoomEvents = new EventEmitter;
function userJoined(username){
chatRoomEvents.on('message', function(message){
document.write(message);
})
}
chatRoomEvents.on('userJoined', userJoined);
All of that headache can be avoided if we rewrite the code like so:
const EventEmitter = require('events').EventEmitter;
const chatRoomEvents = new EventEmitter;
function displayMessage(message){
document.write(message);
}
function userJoined(username){
chatRoomEvents.on('message', displayMessage);
}
chatRoomEvents.on('userJoined', userJoined);
Now if we want to remove the displayMessage function from the message event’s list of handlers:
chatRoomEvents.removeListener('message', displayMessage);
Object Oriented Programming + Event-Driven Programming
The combination of the Object Oriented and Event-driven programming paradigms make for a very valuable combination in a wide variety of situations and it can be beneficial to understand and conceptualize why.