Understanding Event Emitters
Understanding Event Emitters
Event emitters is a core module for Node developers to implement the observer pattern. The observer pattern has the following: an observer, an event and an event emitter.
The flow goes like this:
- A class is created with
class
- A class inherits from the EventEmitter class using
extends
- An instance of an object is created from the class with
new
- An observer (a.k.a. event listener) is created with
.on(eventName, eventHandler)
- An event is emitted with
emit()
and the event handler in the observer is executed.
Consider this simple observer pattern code which creates a
Job
class and then instantiates it. Later on, the object created from the class has an observer/event listener attached (job.on('done'...)
) and an event is emitted/triggered.
simple.js:
const EventEmitter = require('events')
class Job extends EventEmitter {}
job = new Job()
job.on('done', function(timeDone){
console.log('Job was pronounced done at', timeDone)
})
job.emit('done', new Date())
job.removeAllListeners() // remove all observers
The result will be:
Job was pronounced done at
Multiple Event Triggers
Events can be triggered/emitted multiple times. For example, in
knock-knock.js
the knock
event is emitted multiple times.
knock-knock.js:
const EventEmitter = require('events')
class Emitter extends EventEmitter {}
emitter = new Emitter()
emitter.on('knock', function() {
console.log('Who\'s there?')
})
emitter.on('knock', function() {
console.log('Go away!')
})
emitter.emit('knock')
emitter.emit('knock')
The result will be:
Who's there?
Go away!
Who's there?
Go away!
Executing Observer Code Only once
emitter.once(eventName, eventHandler)
will execute observer code just once, no matter how many time this particular event was triggered.
knock-knock-once.js:
const EventEmitter = require('events')
class Emitter extends EventEmitter {}
emitter = new Emitter()
emitter.once('knock', function() {
console.log('Who\'s there?')
})
emitter.emit('knock')
emitter.emit('knock')
The result will be:
Who's there?
Modular Events
The observer pattern is often used to modularize code. A typical usage is to separate the event emitter class definition and the event emission into its own module but allow the observers to be defined in the main program. This allows us to customize the module behavior without changing the module code itself.
In
job.js
, we use a generic job
module that emits a done
event after 700ms. However, in weekly.js
, we can customize the event handler of the observer to do whatever we want once a done
event is triggered.
job.js:
const EventEmitter = require('events')
class Job extends EventEmitter {
constructor(ops) {
super(ops)
this.on('start', ()=>{
this.process()
})
}
process() {
setTimeout(()=>{
// Emulate the delay of the job - async!
this.emit('done', { completedOn: new Date() })
}, 700)
}
}
module.exports = Job
weekly.js:
var Job = require('./job.js')
var job = new Job()
job.on('done', function(details){
console.log('Weekly email job was completed at',
details.completedOn)
})
job.emit('start')
When you run
weekly.js
, the custom logic pertaining to the done
event will be executed from weekly.js
. This way the creators of the job.js
module can keep the module flexible. They don't have to hard code any logic for the done
event in the module. Consumers of the module job.js
, people who write weekly.js
, have the power to customize the behavior for the done
event, and not only for that event. Event emitters can have multiple events: in the middle, at the start, in the end, etc. They can be called (emitted or triggered) multiple times and with data (passed as the second argument to emit()
as can be seen in job.js
). Furthermore, there are methods to list or remove event listeners (observers) or to specify the execution of an event listener (observer) just once (.once()
method).
Documentation: https://nodejs.org/api/events.html
No comments:
Post a Comment