Eventos - Node.js
Muitas funcionalidades do Node.js utilizam uma arquitetura assíncrona baseada em eventos, onde várias ações são executadas em resposta a eventos ocorridos. Nessa arquitetura, objetos especiais chamados emissores de eventos (event emitter) disparam os eventos, e funções específicas - chamadas manipuladores ou ouvintes de eventos - tratam esses eventos.
Disparando Eventos e o Tipo EventEmitter
Para disparar eventos, precisamos de um emissor de eventos. Esse emissor é um objeto do tipo EventEmitter
const EventEmitter = require("events");
// definindo o emissor de eventos
const emitter = new EventEmitter();
O EventEmitter
: registra um novo ouvinte para o eventoon(eventName, listener)
.eventName
: alias paraaddListener(eventName, listener)
. Registra um novo ouvinte para o evento eventName.on()
: dispara um evento. Aceita como parâmetro obrigatório o nome do evento e, opcionalmente, argumentos para o manipulador do evento.emit(eventName, [...args])
: retorna uma matriz com os nomes dos eventos que possuem ouvintes registrados.eventNames()
: retorna o número máximo de ouvintes que podem ser registrados para o emissor de eventos.getMaxListeners()
: retorna o número de ouvintes registrados para o eventolistenerCount(eventName)
.eventName
: retorna uma matriz com os ouvintes do eventolisteners(eventName)
.eventName
: registra um novo ouvinte para o eventoonce(eventName, listener)
, mas o ouvinte será executado no máximo uma vez.eventName
: registra um novo ouvinte para o eventoprependListener(eventName, listener)
e o coloca no início da matriz de ouvintes.eventName
: similar aoprependOnceListener(eventName, listener)
, mas o ouvinte será executado no máximo uma vez.prependListener()
: remove todos os ouvintes do eventoremoveAllListeners([eventName])
.eventName
: remove o ouvinte listener do eventoremoveListener(eventName, listener)
.eventName
: define o número máximo de ouvintes que podem ser registrados para cada evento no emissor de eventos.setMaxListeners(n)
Disparando e Manipulando Eventos
Para disparar um evento no EventEmitter
emit()
app.js
const EventEmitter = require("events");
// definindo o emissor de eventos
const emitter = new EventEmitter();
// nome do evento que será manipulado
const eventName = "greet";
// disparando o evento "greet"
emitter.emit(eventName);
Aqui, é disparado o evento "greet". Os nomes dos eventos são arbitrários.
No entanto, ao disparar esse evento, nada acontecerá, pois ele ainda não possui um manipulador registrado. Para registrar um manipulador de eventos, usamos o método on()
const EventEmitter = require("events");
// definindo o emissor de eventos
const emitter = new EventEmitter();
// nome do evento que será manipulado
const eventName = "greet";
// registrando o manipulador para o evento "greet"
emitter.on(eventName, function() {
console.log("Hello World!");
});
// disparando o evento "greet"
emitter.emit(eventName);
Aqui, a função manipuladora exibe a mensagem "Hello World!" no console.
Vamos executar a aplicação:
c:\app> node app.js Hello World!
Podemos registrar vários manipuladores para um único evento:
const EventEmitter = require("events");
// definindo o emissor de eventos
const emitter = new EventEmitter();
// nome do evento que será manipulado
const eventName = "greet";
// registrando três manipuladores para o evento "greet"
emitter.on(eventName, function() {
console.log("Hello World!");
});
emitter.on(eventName, function() {
console.log("Ciao mondo!");
});
emitter.on(eventName, function() {
console.log("Hallo Welt!");
});
// disparando o evento "greet"
emitter.emit(eventName);
Como resultado, ao disparar o evento, os três manipuladores serão executados:
c:\app> node app.js Hello World! Ciao mondo! Hallo Welt!
Passando Parâmetros para o Evento
Ao chamar um evento, é possível passar um objeto como segundo parâmetro para o método emit()
const EventEmitter = require("events");
const emitter = new EventEmitter();
const eventName = "greet";
emitter.on(eventName, function(data) {
console.log(data); // { message: "Hello World!" }
});
emitter.emit(eventName, { message: "Hello World!" });
Herança de EventEmitter
Podemos operar com objetos para os quais também podemos definir eventos, mas para isso, precisamos associá-los a um objeto EventEmitter
const EventEmitter = require("events");
const eventName = "greet";
emitter.on(eventName, function(data) {
console.log(data);
});
class User extends EventEmitter {
constructor(username) {
super(); // chama o construtor de EventEmitter
this.name = username;
}
sayHi() {
console.log("Hi, I am", this.name);
this.emit(eventName, this.name); // gera o evento, passa o nome para o manipulador
}
}
const tom = new User("Tom");
// adiciona ao objeto tom a manipulação do evento "greet"
// o manipulador espera receber o nome do usuário como parâmetro
tom.on(eventName, function(username) {
console.log("Welcome, ", username);
});
// ao executar o método, o evento "greet" é disparado
tom.sayHi();
Aqui, definimos a classe User
EventEmitter
User
User
sayHi
Como User
EventEmitter
User
on()
sayHi()
Exemplo de execução do programa:
c:\app> node app.js Hi, I am Tom Welcome, Tom
Alternativa à Herança: Passando o Objeto EventEmitter
Como alternativa à herança, podemos passar o objeto EventEmitter
const EventEmitter = require("events");
const emitter = new EventEmitter();
const eventName = "greet";
emitter.on(eventName, function(username) {
console.log("Welcome, ", username);
});
class User {
constructor(username, emitter) {
this.name = username;
this.emitter = emitter;
}
sayHi() {
console.log("Hi, I am", this.name);
this.emitter.emit(eventName, this.name); // gera o evento, passa o nome para o manipulador
}
}
const tom = new User("Tom", emitter);
tom.sayHi();
Nesse exemplo, a classe User
EventEmitter
sayHi()
User
EventEmitter
Esta abordagem evita a necessidade de herança direta, permitindo maior flexibilidade na composição de objetos e sua interação com eventos.
Conclusão
O Node.js fornece um módulo events