In the following chapters, you have opportunities to implement a lot of the events that are built into the various Node.js modules. This section focuses on creating your own custom events as well as implementing listener callbacks that are implemented when an event is emitted.
Events are emitted using an EventEmitter
object. This object is included in the events
module. The emit(eventName, [args])
function triggers the eventName
event and includes any arguments provided. The following code snippet shows how to implement a simple event emitter:
var events = require('events'),
var emitter = new events.EventEmitter();
emitter.emit("simpleEvent");
Occasionally, you will want to add events directly to your JavaScript objects. To do that, you need to inherit the EventEmitter
functionality in your object by calling events.EventEmitter.call(this
) in your object instantiation. You also need to add events.EventEmitter.prototype
to your object prototyping. For example:
Function MyObj(){
Events.EventEmitter.call(this);
}
MyObj.prototype.__proto__ = events.EventEmitter.prototype;
You can then emit events directly from instances of your object. For example:
var myObj = new MyObj();
myObj.emit("someEvent");
Once you have an instance of an object that will emit events, you can add listeners for the events that you care about. You add listeners to an EventEmitter
object by using one of the following functions:
.addListener(eventName, callback): Attaches the callback
function to the object’s listeners. Every time the eventName
event is triggered, the callback
function is placed in the event queue to be executed.
.on(eventName, callback): Same as .addListener()
.
.once(eventName, callback): Only the first time the eventName
event is triggered, the callback
function is placed in the event queue to be executed.
For example, to add a listener to an instance of the MyObject EventEmitter
class defined in the previous section, you would use:
function myCallback(){
. . .
}
var myObject = new MyObj();
myObject.on("someEvent", myCallback);
Listeners are very useful and a vital part of Node.js programming. However, they cause overhead, and you should use them only when necessary. Node.js provides several helper functions on the EventEmitter
object that allow you to manage the listeners that are included:
.listeners(eventName): Returns an array of listener functions attached to the eventName
event.
.setMaxListeners(n): Triggers a warning if more than n
listeners are added to an EventEmitter
object. The default is 10
.
.removeListener(eventName, callback): Removes the callback
function from the eventName
event of the EventEmitter
object.
The code in Listing 4.4 demonstrates the process of implementing listeners and custom event emitters in Node.js. The Account
object is extended to inherit from the EventEmitter
class and provides two methods—deposit
and withdraw
—that both emit the balanceChanged
event. Then in lines 15–31, three callback functions are implemented that are attached to the Account
object instance balanceChanged
event and display various forms of data.
Notice that the checkGoal(acc, goal)
callback is implemented a bit differently than the others. This illustrates how you can pass variables into an event listener function when the event is triggered. Figure 4.7 shows the results of executing the code in Listing 4.4.
01 var events = require('events'),
02 function Account() {
03 this.balance = 0;
04 events.EventEmitter.call(this);
05 this.deposit = function(amount){
06 this.balance += amount;
07 this.emit('balanceChanged'),
08 };
09 this.withdraw = function(amount){
10 this.balance -= amount;
11 this.emit('balanceChanged'),
12 };
13 }
14 Account.prototype.__proto__ = events.EventEmitter.prototype;
15 function displayBalance(){
16 console.log("Account balance: $%d", this.balance);
17 }
18 function checkOverdraw(){
19 if (this.balance < 0){
20 console.log("Account overdrawn!!!");
21 }
22 }
23 function checkGoal(acc, goal){
24 if (acc.balance > goal){
25 console.log("Goal Achieved!!!");
26 }
27 }
28 var account = new Account();
29 account.on("balanceChanged", displayBalance);
30 account.on("balanceChanged", checkOverdraw);
31 account.on("balanceChanged", function(){
32 checkGoal(this, 1000);
33 });
34 account.deposit(220);
35 account.deposit(320);
36 account.deposit(600);
37 account.withdraw(1200);