The EventEmitter object is defined in the events module of Node.js. Directly using the EventEmitter class means performing require('events'). In most cases, you'll be using an existing object that uses EventEmitter internally and you won't require this module. But there are cases where needs dictate implementing an EventEmitter subclass.
Create a file named pulser.js containing the following code:
const EventEmitter = require('events');
class Pulser extends EventEmitter {
start() {
setInterval(() => {
console.log(`${new Date().toISOString()} >>>> pulse`);
this.emit('pulse');
console.log(`${new Date().toISOString()} <<<< pulse`);
}, 1000);
}
}
module.exports = Pulser;
This defines a Pulser class, which inherits from EventEmitter. In older Node.js releases, this would require using util.inherits, but the new class object makes subclassing much simpler.
Another thing to examine is how this.emit in the callback function refers to the Pulser object. Before the ES2015 arrow function, when our callbacks used a regular function, this would not have referred to the Pulser object. Instead, it would have referred to some other object related to the setInterval function. Because it is an arrow function, the this inside the arrow function is the same this as in the outer function.
If you needed to use a function rather than an arrow function, this trick would work:
class Pulser extends EventEmitter {
start() {
var self = this;
setInterval(function() {
self.emit(...);
});
}
}
What's different is the assignment of this to self. The value of this inside the function is different, but the value of self remains the same in every enclosed scope. This widely-used trick is less necessary now that we have arrow functions.
If you want a simple EventEmitter, but with your own class name, the body of the extended class can be empty:
class HeartBeat extends EventEmitter {}
const beatMaker = new HeartBeat();
The purpose of the Pulser class is sending a timed event, once a second, to any listeners. The start method uses setInterval to kick off repeated callback execution, scheduled for every second, calling emit to send the pulse events to any listeners.
Now, let's see how to use the Pulser object. Create a new file, called pulsed.js, containing:
const Pulser = require('./pulser');
// Instantiate a Pulser object
const pulser = new Pulser();
// Handler function
pulser.on('pulse', () => {
console.log(`${new Date().toISOString()} pulse received`);
});
// Start it pulsing
pulser.start();
Here, we create a Pulser object and consume its pulse events. Calling pulser.on('pulse') sets up connections for the pulse events to invoke the callback function. It then calls the start method to get the process going.
Enter this into a file and name the file pulsed.js. When you run it, you should see the following output:
$ node pulsed.js
2017-12-03T06:24:10.272Z >>>> pulse
2017-12-03T06:24:10.275Z pulse received
2017-12-03T06:24:10.276Z <<<< pulse
2017-12-03T06:24:11.279Z >>>> pulse
2017-12-03T06:24:11.279Z pulse received
2017-12-03T06:24:11.279Z <<<< pulse
2017-12-03T06:24:12.281Z >>>> pulse
2017-12-03T06:24:12.281Z pulse received
2017-12-03T06:24:12.282Z <<<< pulse
That gives you a little practical knowledge of the EventEmitter class. Let's now look at its operational theory.