2022-04-23 13:26:53 +01:00
|
|
|
---
|
2022-09-06 15:44:40 +01:00
|
|
|
categories:
|
|
|
|
- Programming Languages
|
2022-04-23 13:26:53 +01:00
|
|
|
tags:
|
|
|
|
- backend
|
|
|
|
- node-js
|
|
|
|
---
|
2022-09-06 15:44:40 +01:00
|
|
|
|
2022-11-16 17:57:44 +00:00
|
|
|
# Node.js `events` module
|
2022-09-06 15:44:40 +01:00
|
|
|
|
2024-02-02 15:58:13 +00:00
|
|
|
In most cases you won't interact with the `events` module directly since other
|
|
|
|
modules and third-party modules are abstractions on top of it. For instance the
|
|
|
|
`http` module is using events under the hood to handle requests and responses.
|
|
|
|
|
|
|
|
Another way of putting this is to say that all events in Node inherit from the
|
|
|
|
`EventEmitter` constructor, which is the class you instantiate to create a new
|
|
|
|
event. At bottom everything in Node is an event with a callback, created via
|
|
|
|
event emitters.
|
|
|
|
|
|
|
|
Because Node's runtime is
|
|
|
|
[event-driven](/Programming_Languages/NodeJS/Architecture/Event_loop.md), it is
|
|
|
|
event-emitter cycles that are being processed by the Event Loop, although you
|
|
|
|
may know them as `fs` or `http` (etc) events. The call stack that the Event Loop
|
|
|
|
works through is just a series of event emissions and their associated
|
|
|
|
callbacks.
|
2022-04-23 13:26:53 +01:00
|
|
|
|
|
|
|
## Event Emitters
|
|
|
|
|
2024-02-02 15:58:13 +00:00
|
|
|
- All objects that emit events are instances of the `EventEmitter` class. This
|
|
|
|
object exposes an `eventEmitter.on()` function that allows one or more
|
|
|
|
functions to be attached to named events emitted by the object.
|
2022-09-06 15:44:40 +01:00
|
|
|
- These functions are **listeners** of the emitter.
|
2022-04-23 13:26:53 +01:00
|
|
|
|
|
|
|
## Basic syntax
|
|
|
|
|
2022-09-06 15:44:40 +01:00
|
|
|
```js
|
2022-11-16 17:57:44 +00:00
|
|
|
const EventEmitter = require("events"); // import the module
|
2022-04-23 13:26:53 +01:00
|
|
|
|
2022-09-06 15:44:40 +01:00
|
|
|
// Raise an event
|
2022-11-16 17:57:44 +00:00
|
|
|
const emitter = new EventEmitter("messageLogged");
|
2022-04-23 13:26:53 +01:00
|
|
|
|
|
|
|
// Register a listener
|
2022-11-16 17:57:44 +00:00
|
|
|
emitter.on("messagedLogged", function () {
|
|
|
|
console.log("The listener was called.");
|
2022-09-06 15:44:40 +01:00
|
|
|
});
|
|
|
|
```
|
2022-04-23 13:26:53 +01:00
|
|
|
|
2024-02-02 15:58:13 +00:00
|
|
|
- If we ran this file, we would see `The listener was called` logged to the
|
|
|
|
console.
|
2022-09-06 15:44:40 +01:00
|
|
|
- Without a listener (similar to a subscriber in Angular) nothing happens.
|
2024-02-02 15:58:13 +00:00
|
|
|
- When the emission occurs the emitter works _synchronously_ through each
|
|
|
|
listener function that is attached to it.
|
2022-04-23 13:26:53 +01:00
|
|
|
|
|
|
|
## Event arguments
|
|
|
|
|
2024-02-02 15:58:13 +00:00
|
|
|
- Typically we would not just emit a string, we would attach an object to the
|
|
|
|
emitter to pass more useful data. This data is called an **Event Argument**.
|
2022-09-06 15:44:40 +01:00
|
|
|
- Refactoring the previous example:
|
2022-04-23 13:26:53 +01:00
|
|
|
|
2022-09-06 15:44:40 +01:00
|
|
|
```js
|
|
|
|
// Raise an event
|
2022-11-16 17:57:44 +00:00
|
|
|
const emitter = new EventEmitter("messageLogged", function (eventArg) {
|
|
|
|
console.log("Listener called", eventArg);
|
2022-09-06 15:44:40 +01:00
|
|
|
});
|
2022-04-23 13:26:53 +01:00
|
|
|
|
|
|
|
// Register a listener
|
2022-11-16 17:57:44 +00:00
|
|
|
emitter.on("messagedLogged", { id: 1, url: "http://www.example.com" });
|
2022-09-06 15:44:40 +01:00
|
|
|
```
|
2022-04-23 13:26:53 +01:00
|
|
|
|
|
|
|
## Extending the `EventEmitter` class
|
|
|
|
|
2024-02-02 15:58:13 +00:00
|
|
|
- It's not best practice to call the EventEmitter class directly in `app.js`. If
|
|
|
|
we want to use the capabilities of the class we should create our own module
|
|
|
|
that extends `EventEmitter`, inheriting its functionality with specific
|
|
|
|
additional features that we want to add.
|
2022-09-06 15:44:40 +01:00
|
|
|
- So, refactoring the previous example:
|
2022-04-23 13:26:53 +01:00
|
|
|
|
2022-09-06 15:44:40 +01:00
|
|
|
```js
|
2022-04-23 13:26:53 +01:00
|
|
|
// File: Logger.js
|
|
|
|
|
2022-11-16 17:57:44 +00:00
|
|
|
const EventEmitter = require("events");
|
2022-04-23 13:26:53 +01:00
|
|
|
|
|
|
|
class Logger extends EventEmitter {
|
2022-09-06 15:44:40 +01:00
|
|
|
log(message) {
|
|
|
|
console.log(message);
|
2022-11-16 17:57:44 +00:00
|
|
|
this.emit("messageLogged", { id: 1, url: "http://www.example.com" });
|
2022-09-06 15:44:40 +01:00
|
|
|
}
|
2022-04-23 13:26:53 +01:00
|
|
|
}
|
2022-09-06 15:44:40 +01:00
|
|
|
```
|
2022-04-23 13:26:53 +01:00
|
|
|
|
2024-02-02 15:58:13 +00:00
|
|
|
_The `this` in the `log` method refers to the properties and methods of
|
|
|
|
`EventEmitter` which we have extended._
|
2022-04-23 13:26:53 +01:00
|
|
|
|
2024-02-02 15:58:13 +00:00
|
|
|
- We also need to refactor our listener code within `app.js` so that it calls
|
|
|
|
the extended class rather than the `EventEmitter` class directly:
|
2022-04-23 13:26:53 +01:00
|
|
|
|
2022-09-06 15:44:40 +01:00
|
|
|
```js
|
|
|
|
// File app.js
|
2022-04-23 13:26:53 +01:00
|
|
|
|
|
|
|
const Logger = require('./Logger')
|
|
|
|
const logger = new Logger()
|
|
|
|
|
|
|
|
logger.on('messageLogged', function(eventArg){
|
|
|
|
console.log('Listener called', eventArg)
|
|
|
|
}
|
2022-09-06 15:44:40 +01:00
|
|
|
|
2022-04-23 13:26:53 +01:00
|
|
|
logger.log('message')
|
2022-09-06 15:44:40 +01:00
|
|
|
```
|