Event Bus e padrão Observer em JavaScript (Node.js)
No desenvolvimento moderno com Node.js, surge frequentemente a necessidade de organizar uma interação fracamente acoplada entre os componentes da aplicação. Para resolver esse problema, o padrão Observer e sua implementação prática — Event Bus (Barramento de Eventos) — são ideais. Neste artigo, vamos detalhar o que é Event Bus, como ele se relaciona com o padrão Observer e criar nossa própria implementação em JavaScript puro para Node.js.
O que é o padrão Observer?
O padrão Observer define uma relação "um para muitos" entre objetos. Quando um objeto (sujeito ou editor) altera seu estado, todos os objetos dependentes dele (observadores ou assinantes) são automaticamente notificados. No Node.js, esse padrão está integrado ao núcleo através da classe EventEmitter.
Componentes principais do padrão:
- Subject (Sujeito) — objeto que gera eventos.
- Observer (Observador) — objeto que se inscreve nos eventos.
- Subscription (Inscrição) — mecanismo de registro do observador no sujeito.
O que é Event Bus?
Event Bus é um mediador centralizado que implementa o padrão Observer. Em vez de cada componente se inscrever diretamente em outro componente, todos se comunicam através de um único barramento de eventos. Isso oferece as seguintes vantagens:
- Baixo acoplamento dos componentes.
- Facilidade para adicionar novos assinantes sem alterar o código do editor.
- Possibilidade de gerenciamento centralizado de eventos (logging, filtragem, depuração).
EventEmitter nativo no Node.js
O Node.js fornece o módulo nativo events, que contém a classe EventEmitter. Esta é uma implementação pronta de Event Bus. Vamos ver um exemplo básico:
const EventEmitter = require('events');const eventBus = new EventEmitter();
// Inscrevendo-se no evento 'user:login'eventBus.on('user:login', (user) => { console.log(`Usuário ${user.name} fez login`);});
// Inscrevendo-se com outro manipuladoreventBus.on('user:login', (user) => { console.log(`Enviando e-mail de boas-vindas para ${user.email}`);});
// Gerando o eventoeventBus.emit('user:login', { name: 'Ivan', email: 'ivan@example.com' });// Saída:// Usuário Ivan fez login// Enviando e-mail de boas-vindas para ivan@example.comCriando seu próprio Event Bus
Às vezes, o EventEmitter nativo não é suficiente — por exemplo, se for necessário adicionar suporte a manipuladores assíncronos, prioridades ou tipagem estrita. Vamos criar nossa própria implementação de Event Bus do zero:
class EventBus { constructor() { this.events = {}; }
// Inscrição em um evento on(eventName, callback) { if (!this.events[eventName]) { this.events[eventName] = []; } this.events[eventName].push(callback); // Retorna uma função para cancelar a inscrição return () => { this.events[eventName] = this.events[eventName] .filter(cb => cb !== callback); }; }
// Inscrição em evento único once(eventName, callback) { const wrapper = (...args) => { callback(...args); this.off(eventName, wrapper); }; this.on(eventName, wrapper); }
// Geração de evento emit(eventName, ...args) { const callbacks = this.events[eventName]; if (!callbacks) return false; callbacks.forEach(callback => { try { callback(...args); } catch (error) { console.error(`Erro no manipulador do evento ${eventName}:`, error); } }); return true; Também na biblioteca
Trabalho com datas em Kotlin: bibliotecas e ferramentas (Kotlinx-datetime, Joda-Time, java.time)
GuzzleHTTP/Promises PHP: guia completo com exemplos práticos
Geração de relatórios PDF em TypeScript: bibliotecas e ferramentas
Geração de PDF em C++: visão geral das bibliotecas e exemplos de código
Envio de SMS em Go (Golang): integração com API de biblioteca