Atualizado: 02/01/2025

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, definido no módulo "events":

const EventEmitter = require("events");
// definindo o emissor de eventos
const emitter = new EventEmitter();

O EventEmitter fornece vários métodos para gerenciar os manipuladores de eventos:

  • on(eventName, listener): registra um novo ouvinte para o evento eventName.

  • addListener(eventName, listener): alias para on(). Registra um novo ouvinte para o evento eventName.

  • emit(eventName, [...args]): dispara um evento. Aceita como parâmetro obrigatório o nome do evento e, opcionalmente, argumentos para o manipulador do evento.

  • eventNames(): retorna uma matriz com os nomes dos eventos que possuem ouvintes registrados.

  • getMaxListeners(): retorna o número máximo de ouvintes que podem ser registrados para o emissor de eventos.

  • listenerCount(eventName): retorna o número de ouvintes registrados para o evento eventName.

  • listeners(eventName): retorna uma matriz com os ouvintes do evento eventName.

  • once(eventName, listener): registra um novo ouvinte para o evento eventName, mas o ouvinte será executado no máximo uma vez.

  • prependListener(eventName, listener): registra um novo ouvinte para o evento eventName e o coloca no início da matriz de ouvintes.

  • prependOnceListener(eventName, listener): similar ao prependListener(), mas o ouvinte será executado no máximo uma vez.

  • removeAllListeners([eventName]): remove todos os ouvintes do evento eventName.

  • removeListener(eventName, listener): remove o ouvinte listener do evento eventName.

  • setMaxListeners(n): define o número máximo de ouvintes que podem ser registrados para cada evento no emissor de eventos.

Disparando e Manipulando Eventos

Para disparar um evento no EventEmitter, usamos o método emit(), passando o nome do evento. Vamos definir o seguinte código no arquivo 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(), passando o nome do evento e a função manipuladora. Vamos manipular o evento "greet":

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(). Esse objeto é então passado para a função manipuladora do evento:

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. Por exemplo:

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 que herda de EventEmitter. O construtor da classe User recebe o nome do usuário. Na classe User, definimos o método sayHi, que gera o evento "greet" e passa o nome do usuário para o manipulador de eventos.

Como User herda de EventEmitter, os objetos User também possuem o método on(), através do qual podemos definir um manipulador de eventos. Esse manipulador será chamado quando o método sayHi() for executado.

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 para outro objeto:

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 recebe um objeto EventEmitter como parâmetro do construtor. O método sayHi() da classe User utiliza o objeto EventEmitter passado para disparar o evento "greet", passando o nome do usuário para o manipulador de eventos.

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 que permite a criação de emissores de eventos e a manipulação de eventos. A arquitetura de eventos é amplamente utilizada no Node.js, e muitas funcionalidades do Node.js são baseadas nessa arquitetura.

Política de Privacidade

Copyright © www.programicio.com Todos os direitos reservados

É proibida a reprodução do conteúdo desta página sem autorização prévia do autor.

Contato: programicio@gmail.com