DEV Community

Abel Costa
Abel Costa

Posted on

NodeJs EventEmitter

O uso comum de javascript: browser, nos permite entender que grande parte da interação que o usuário faz com a máquina se dá através de eventos, exemplos de eventos são:

  • cliques de mouse
  • apertar um botão no teclado
  • mover o mouse

Do lado do backend entretanto, podemos ter outros tipos de eventos, o NodeJs nos permite construir um sistema de eventos similiar, usando o módulo nativo events. Esse módulo fornece a classe EventEmitter que pode ser usada para lidar com eventos.

Dentro da família de manipuladores de eventos do NodeJs o EventEmitter é o mais popular, isso porque tudo que acontece no NodeJs acontece a partir de eventos. O EventEmitter é usado para ações contínuas.

Na verdade EventEmitter é uma classe que nos permite implementar o pattern pub/sub no NodeJS. Com um event emitter, nós podemos simplesmente lançar um novo evento de uma parte distinta da aplicação e o listener vai escutar esse evento lançado e performar uma determinada ação para aquele evento.

Criando um EventEmitter

Para lidar com um EventEmitter temos de instanciar a classe que faz parte do módulo events, nativo do NodeJS, a classe vem com vários métodos, os mais usados são:

  • addListener
  • once
  • on
  • off
  • removeListener
  • emit

Manipulando os eventos com o EventEmitter

A melhor forma de manipular nossos eventos com o EventEmitter é criando uma classe que extenda a classe original do EventEmitter que faz parte do módulo do NodeJs. Como podemos ver no código abaixo:

const EventEmitter = require('events');
const { clearInterval } = require('timers');

class Emitter extends EventEmitter {

}

const emitter = new Emitter();

const event = 'usuario:click';

emitter.on(event, function (click) {
  switch (click) {
    case 'barra de rolagem':
      console.log(`está subindo ou descendo a página`);
      break;
    case 'barra lateral':
      console.log(`está rolando a página para o lado`);
      break;
    case 'botao submit':
      console.log(`enviando informações em um formulário`);
      break;
    case 'botao cancel':
      console.log(`cancelando uma ação`);
      break;
    default:
      break;
  }
});

const userEvents = ['barra de rolagem', 'barra lateral', 'botao submit', 'botao cancel'];

setInterval(() => {
  const random = Math.floor(Math.random() * (userEvents.length - 1));
  emitter.emit(event, userEvents[random]);
}, 1000);
Enter fullscreen mode Exit fullscreen mode

Teremos um log diferente para cada um dos eventos que um usuário pode executar.

Top comments (4)

Collapse
 
urielsouza29 profile image
Uriel dos Santos Souza

Tenho uma duvida que não é solucionada em lugar algum.

Em muitos lugares nos falam pra gente remover os eventos dentro do node.

Mas nunca dizem em que situação e pq devemos fazer isso!
Ex:
Vamos dizer que uma API cria um usuário e usando eventos para mandar um email.

Evento criado em um arquivo separado.
const emitter = new Emitter();
emitter.on('email', function (click) {}) ...
Exportado

Depois importado onde será preciso para enviar o email

Toda vez que um novo usuário é criado salvo no BD e
emitter.emit('email', userid);

E isso fica lá sempre.

Quando se deve remover?
E se remover como por novo?
Precisa mesmo?
Se não remover o que acontece?

Abraços

Collapse
 
abelsouzacosta profile image
Abel Costa • Edited

Primeiramente desculpa a demora de ter aparecido por aqui, tava estudando muito e tava bastante agarrado no trabalho.

Na verdade o que você quer saber é quando remover um event listener, não um evento.

Bem, pra responder a sua pergunta de uma maneira simples eu vou abstrair muito o conceito de máquina de estados aqui (até mesmo porque não é uma coisa simples de ser explicada) e por isso talvez a explicação fique pobre, mas espero que você entenda.

Basicamente quando você tá criando um listener o Node vai alocar uma thread dentro do thread pool só para lidar com ele, uma vez que listeners são usados para lidar com processos assíncronos. Ao criar o listener ele vai ficar escutando os eventos que acontecem que dão match com o que ele tem que ouvir, assim sendo a thread na qual ele fica alocado sempre vai ficar em estado de ready. Isso impede que a thread possa ser desalocada porque threads em estado de pronto não podem ser interrompidas, ou seja, enquanto o listener não for removido a thread nunca atinge o estado de done, terminado, onde ela pode ser encerrada para a criação de uma nova.

Então de forma direta: quando remover um event listener?

Sempre.

Lembre-se que código é executado de forma encadeada, ou seja, um método chama outro método, podemos abstrair isso de forma a pensar que o código é executado da forma clássica, da esquerda para a direta de cima para baixo, então o fluxo ideal ao se trabalhar com um event listener é remover sempre depois dele executar a tarefa que foi determinada para ele.

Vou exemplificar com um pequeno trecho de código:

const emitter = require("EventEmitter")
// criando o listener
const emailHandler = (email) => { console.log(`sending a email`) };

emitter.addListener('email', emailHandler)

emitter.removeListener(emailHandler)
Enter fullscreen mode Exit fullscreen mode

.on é nada além de um alias para addListener, recomendo sempre usar o segundo porque a nível de escrita ele é mais claro que o primeiro.

Bem espero que tenha respondido sua pergunta...

Porém nunca tome algo que eu escrevo como 100% corretas, é apenas um recorte do meu entendimento dentro de um determinado espaço de tempo, mas o conhecimento se transforma com o tempo, naturalmente.

Collapse
 
urielsouza29 profile image
Uriel dos Santos Souza • Edited

Oi, eu entendi. Mas ainda me falta algo mais.
Você tem links disso pra eu poder ler?
Foi uma ótima explicação!

Abraços

Thread Thread
 
urielsouza29 profile image
Uriel dos Santos Souza

Eu até fiz um teste aqui:
github.com/Uriel29/eventEmitter/up...
Ele remove, mas remove pra sempre.
Imagina a situação de um cadastro de usuário que precisa enviar um evento sempre que o cadastro acontecer. Se eu remover. Já era...

ou tem outra forma de recolocar tudo novamente?