Node.js: EventEmitter

Última atualização: 2026-08-26

Alice é uma engenheira de back-end que desenvolve um sistema de pedidos para comércio eletrônico. Inicialmente, ela fez com que a função de criação de pedidos chamasse diretamente três módulos — envio de e-mails, atualização de estoque e registro em log —, mas isso significava que, toda vez que ela adicionava um novo recurso, precisava modificar o código principal dos pedidos, tornando o sistema cada vez mais frágil. Posteriormente, ela refatorou o código usando o EventEmitter: o módulo de pedidos agora é responsável apenas por acionar o evento order:created, enquanto cada serviço escuta de forma independente, sem interferir uns nos outros. Adicionar “notificações por SMS” requer apenas a inclusão de um ouvinte, sem nenhuma alteração no código principal. Essa arquitetura de publicação-assinatura reduziu os custos de manutenção do sistema em 60%.

1. O que você vai aprender



2. Conceitos básicos do EventEmitter

EventEmitter é a classe fundamental para a arquitetura orientada a eventos do Node.js, localizada no módulo events. Ela mantém um mapeamento entre nomes de eventos e matrizes de funções de escuta. Quando emit() aciona um evento, todas as funções de escuta registradas são executadas sincronicamente na ordem em que foram registradas.

100%
flowchart LR
    subgraph Emitter["EventEmitter(Posted by)"]
        E1[emit - order:created]
    end
    subgraph Listeners["Listener(Subscribers)"]
        L1[Listener1:Send an Email]
        L2[Listener2:Update Inventory]
        L3[Listener3:Log Entry]
    end
    E1 --> L1
    E1 --> L2
    E1 --> L3
    style Emitter fill:#e1f5fe
    style Listeners fill:#f3e5f5
JAVASCRIPT
const EventEmitter = require('events');

const emitter = new EventEmitter();

emitter.on('greet', (name) => {
  console.log(`Hello, ${name}!`);
});

emitter.emit('greet', 'Alice');
TEXT 📖 Somente leitura
Hello, Alice!


3. Referência rápida aos métodos comuns do EventEmitter

Método Descrição Valor de retorno
on(event, listener) Registra um ouvinte; pode ser registrado várias vezes Instância de EventEmitter
once(event, listener) Registrar um ouvinte de uso único que é removido automaticamente ao ser acionado Instância do EventEmitter
emit(event, ...args) Acionar um evento, passar parâmetros true Possui um ouvinte / false Não possui ouvinte
off(event, listener) Remover um ouvinte especificado Instância de EventEmitter
removeListener(event, listener) Igual a off(), API antiga Instância de EventEmitter
removeAllListeners([event]) Remover ouvintes de todos os eventos ou de eventos específicos Instância de EventEmitter
prependListener(event, listener) Adicionar um ouvinte ao início da fila Instância do EventEmitter
prependOnceListener(event, listener) Adicionar um ouvinte de uso único no início Instância do EventEmitter
listeners(event) Retorna o array de ouvintes de eventos Function[]
listenerCount(event) Número de ouvintes number
setMaxListeners(n) Definir o número máximo de ouvintes para um único evento Instância do EventEmitter
getMaxListeners() Obter o número máximo de ouvintes number
eventNames() Retornar todos os nomes de eventos registrados `(string
rawListeners(event) Retorna o ouvinte original marcado com once Function[]

▶ Exemplo: Uso básico de on/emit/off

JAVASCRIPT
const EventEmitter = require('events');
const emitter = new EventEmitter();

function onOrderCreated(order) {
  console.log(`[Listener] Order created: #${order.id}`);
}

emitter.on('order:created', onOrderCreated);

emitter.emit('order:created', { id: 1001, product: 'Laptop', qty: 2 });

emitter.off('order:created', onOrderCreated);

const hasListeners = emitter.emit('order:created', { id: 1002, product: 'Mouse', qty: 5 });
console.log('Has listeners:', hasListeners);
▶ Experimente
TEXT 📖 Somente leitura
[Listener] Order created: #1001
Has listeners: false


4. Comparação entre on, once e prependListener

Características on() once() prependListener()
Número de gatilhos Aciona sempre Aciona apenas uma vez e, em seguida, é removido automaticamente Aciona sempre
Local de registro Fim da fila Fim da fila Início da fila (executado primeiro)
Cenários típicos Monitoramento contínuo de mensagens Inicialização realizada apenas uma vez Processamento de alta prioridade (por exemplo, registro em log)
Remoção automática Não Sim Não
Corresponde à versão descartável once() prependOnceListener()

▶ Exemplo: “once” é acionado apenas uma vez

JAVASCRIPT
const EventEmitter = require('events');
const emitter = new EventEmitter();

emitter.once('server:ready', (port) => {
  console.log(`Server initialized on port ${port}`);
});

emitter.emit('server:ready', 3000);
emitter.emit('server:ready', 3001);
console.log('Second emit had no effect');
▶ Experimente
TEXT 📖 Somente leitura
Server initialized on port 3000
Second emit had no effect

▶ Exemplo: o prependListener é executado primeiro

JAVASCRIPT
const EventEmitter = require('events');
const emitter = new EventEmitter();

emitter.on('data', () => console.log('Normal listener'));
emitter.prependListener('data', () => console.log('Priority listener'));

emitter.emit('data');
▶ Experimente
TEXT 📖 Somente leitura
Priority listener
Normal listener


5. Gerenciamento de ouvintes de eventos

Por padrão, o Node.js permite no máximo 10 ouvintes por evento; ultrapassar esse limite acionará um aviso de vazamento de memória. Esse não é um limite rígido, mas sim um lembrete para que os desenvolvedores verifiquem se não se esqueceram de remover algum ouvinte.

▶ Exemplo: listenerCount e avisos de vazamento de memória

JAVASCRIPT
const EventEmitter = require('events');
const emitter = new EventEmitter();

for (let i = 0; i < 12; i++) {
  emitter.on('log', () => console.log(`Listener ${i}`));
}

console.log('Listener count:', emitter.listenerCount('log'));
console.log('Max listeners:', emitter.getMaxListeners());
▶ Experimente
TEXT 📖 Somente leitura
(node:1234) MaxListenersExceededWarning: Possible EventEmitter memory leak detected. 12 log listeners added. Use emitter.setMaxListeners() to increase limit
Listener count: 12
Max listeners: 10

▶ Exemplo: Ajustando o limite superior com setMaxListeners

JAVASCRIPT
const EventEmitter = require('events');
const emitter = new EventEmitter();

emitter.setMaxListeners(20);

for (let i = 0; i < 15; i++) {
  emitter.on('task', () => {});
}

console.log('No warning: max set to', emitter.getMaxListeners());
console.log('Listener count:', emitter.listenerCount('task'));
▶ Experimente
TEXT 📖 Somente leitura
No warning: max set to 20
Listener count: 15

▶ Exemplo: limpeza com removeAllListeners

JAVASCRIPT
const EventEmitter = require('events');
const emitter = new EventEmitter();

emitter.on('tick', () => console.log('tick A'));
emitter.on('tick', () => console.log('tick B'));
emitter.on('tock', () => console.log('tock A'));

emitter.removeAllListeners('tick');

console.log('tick listeners:', emitter.listenerCount('tick'));
console.log('tock listeners:', emitter.listenerCount('tock'));
▶ Experimente
TEXT 📖 Somente leitura
tick listeners: 0
tock listeners: 1


6. Classes de eventos personalizadas

No desenvolvimento prático, é comum herdar de EventEmitter para criar classes de eventos com semântica de negócios, em vez de usar instâncias de EventEmitter diretamente.

▶ Exemplo: Criando uma classe de evento de pedido ao estender a classe EventEmitter

JAVASCRIPT
const EventEmitter = require('events');

class OrderEmitter extends EventEmitter {
  create(order) {
    this.emit('order:created', order);
  }

  cancel(orderId) {
    this.emit('order:cancelled', { orderId, cancelledAt: new Date().toISOString() });
  }

  ship(orderId, trackingNo) {
    this.emit('order:shipped', { orderId, trackingNo });
  }
}

const orderEvents = new OrderEmitter();

orderEvents.on('order:created', (order) => {
  console.log(`[Email] Confirmation for order #${order.id}`);
});

orderEvents.on('order:created', (order) => {
  console.log(`[Inventory] Deduct ${order.qty}x ${order.product}`);
});

orderEvents.on('order:cancelled', ({ orderId }) => {
  console.log(`[Refund] Processing refund for #${orderId}`);
});

orderEvents.create({ id: 2001, product: 'Headphones', qty: 3 });
orderEvents.cancel(2001);
▶ Experimente
TEXT 📖 Somente leitura
[Email] Confirmation for order #2001
[Inventory] Deduct 3x Headphones
[Refund] Processing refund for #2001


7. O error e o tratamento de erros

O EventEmitter possui um evento especial error: se o evento error for acionado, mas não houver ouvintes, o Node.js lançará uma exceção e encerrará o processo. Essa é a regra de segurança mais importante do EventEmitter.

▶ Exemplo: Falha no processo devido à incapacidade de lidar com um erro

JAVASCRIPT
const EventEmitter = require('events');
const emitter = new EventEmitter();

emitter.emit('error', new Error('Database connection failed'));
▶ Experimente
TEXT 📖 Somente leitura
events.js:291
      throw er; // Unhandled 'error' event
      ^
Error: Database connection failed
    at Object.<anonymous> (app.js:4:20)

▶ Exemplo: Como lidar corretamente com o evento error

JAVASCRIPT
const EventEmitter = require('events');
const emitter = new EventEmitter();

emitter.on('error', (err) => {
  console.error(`[Error Handler] ${err.message}`);
});

emitter.emit('error', new Error('Database connection failed'));
console.log('Process continues running');
▶ Experimente
TEXT 📖 Somente leitura
[Error Handler] Database connection failed
Process continues running


8. Comparação entre abordagens orientadas a eventos, callbacks e promessas

Recurso Orientado a eventos (EventEmitter) Callback Promise / async-await
Modo de comunicação Um para muitos (publicação-assinatura) Um para um Um para um
Número de acionadores Pode ser acionado várias vezes Aciona apenas uma vez É resolvido apenas uma vez
Cenários típicos Transmissão de mensagens, mudanças de estado Conclusão de operações de E/S Resultados finais de operações assíncronas
Acoplamento Baixo (o editor não conhece o assinante) Alto (o chamador deve conhecer o destinatário da chamada de retorno) Médio (encadeamento ou await)
Cancelável Pode ser removido com off() Não cancelável Não cancelável (pode ser ignorado)
Suporte integrado Módulo events Convenções globais Linguagem integrada
Tratamento de erros error Evento Callback de prioridade de erro .catch() / try-catch


9. Módulos integrados do Node.js que utilizam o EventEmitter

Muitos dos módulos integrados do Node.js herdam de EventEmitter; quase todos os objetos de fluxo, servidor e processo são emissores de eventos.

Módulo/Objeto Herda de EventEmitter Eventos comuns
net.Server Sim connection, close, error
http.Server Sim request, connection, close
stream.Readable Sim data, end, error, close
stream.Writable Sim drain, finish, error, close
net.Socket Sim data, connect, end, error
process Sim exit, uncaughtException, SIGINT
child_process.ChildProcess Sim exit, message, error, close
fs.watch() Voltar ao EventEmitter change, error

▶ Exemplo: http.Server usando EventEmitter

JAVASCRIPT
const http = require('http');

const server = http.createServer();

server.on('request', (req, res) => {
  console.log(`[Request] ${req.method} ${req.url}`);
  res.end('OK');
});

server.on('connection', (socket) => {
  console.log(`[Connection] New client from ${socket.remoteAddress}`);
});

server.listen(3000, () => {
  console.log('Server listening on port 3000');
});
▶ Experimente
TEXT 📖 Somente leitura
Server listening on port 3000
[Connection] New client from ::ffff:127.0.0.1
[Request] GET /

▶ Exemplo: Fluxo legível usando o EventEmitter

JAVASCRIPT
const { Readable } = require('stream');

const readable = Readable.from(['Hello', ' ', 'World']);

readable.on('data', (chunk) => {
  console.log(`[Data] Received: "${chunk}"`);
});

readable.on('end', () => {
  console.log('[End] No more data');
});
▶ Experimente
TEXT 📖 Somente leitura
[Data] Received: "Hello"
[Data] Received: " "
[Data] Received: "World"
[End] No more data


10. Exemplo abrangente: Agendador de tarefas orientado a eventos

Crie uma classe TaskScheduler que suporte o registro de tarefas, o acionamento de eventos e as respostas de vários ouvintes. Simule a cadeia de notificações que ocorre após a criação de uma tarefa em um cenário real.

JAVASCRIPT
const EventEmitter = require('events');

class TaskScheduler extends EventEmitter {
  constructor() {
    super();
    this.tasks = new Map();
    this.nextId = 1;
  }

  addTask(name, payload) {
    const id = this.nextId++;
    const task = {
      id,
      name,
      payload,
      createdAt: new Date().toISOString(),
      status: 'pending'
    };
    this.tasks.set(id, task);
    this.emit('task:added', task);
    return task;
  }

  startTask(id) {
    const task = this.tasks.get(id);
    if (!task) {
      this.emit('error', new Error(`Task #${id} not found`));
      return;
    }
    task.status = 'running';
    task.startedAt = new Date().toISOString();
    this.emit('task:started', task);
  }

  completeTask(id, result) {
    const task = this.tasks.get(id);
    if (!task) {
      this.emit('error', new Error(`Task #${id} not found`));
      return;
    }
    task.status = 'completed';
    task.result = result;
    task.completedAt = new Date().toISOString();
    this.emit('task:completed', task);
  }

  failTask(id, reason) {
    const task = this.tasks.get(id);
    if (!task) {
      this.emit('error', new Error(`Task #${id} not found`));
      return;
    }
    task.status = 'failed';
    task.reason = reason;
    task.failedAt = new Date().toISOString();
    this.emit('task:failed', task);
  }

  getStats() {
    const stats = { total: this.tasks.size, pending: 0, running: 0, completed: 0, failed: 0 };
    for (const task of this.tasks.values()) {
      stats[task.status]++;
    }
    return stats;
  }
}

const scheduler = new TaskScheduler();

scheduler.on('error', (err) => {
  console.error(`[ERROR] ${err.message}`);
});

scheduler.on('task:added', (task) => {
  console.log(`[Logger] Task #${task.id} "${task.name}" added at ${task.createdAt}`);
});

scheduler.on('task:added', (task) => {
  console.log(`[Notifier] New task available: ${task.name}`);
});

scheduler.on('task:started', (task) => {
  console.log(`[Executor] Task #${task.id} is now running...`);
});

scheduler.on('task:completed', (task) => {
  console.log(`[Reporter] Task #${task.id} completed with result: ${task.result}`);
  console.log(`[Cleaner] Releasing resources for task #${task.id}`);
});

scheduler.on('task:failed', (task) => {
  console.log(`[Alerter] Task #${task.id} failed: ${task.reason}`);
});

console.log('=== Adding Tasks ===');
const t1 = scheduler.addTask('Data Import', { source: 'api.example.com', rows: 5000 });
const t2 = scheduler.addTask('Report Generation', { format: 'PDF', quarter: 'Q4' });

console.log('\n=== Starting Tasks ===');
scheduler.startTask(t1.id);
scheduler.startTask(t2.id);

console.log('\n=== Completing / Failing Tasks ===');
scheduler.completeTask(t1.id, '5000 rows imported successfully');
scheduler.failTask(t2.id, 'PDF renderer service unavailable');

console.log('\n=== Stats ===');
console.log(scheduler.getStats());

console.log('\n=== Invalid Operation ===');
scheduler.startTask(999);
TEXT 📖 Somente leitura
=== Adding Tasks ===
[Logger] Task #1 "Data Import" added at 2025-07-03T10:00:00.000Z
[Notifier] New task available: Data Import
[Logger] Task #2 "Report Generation" added at 2025-07-03T10:00:01.000Z
[Notifier] New task available: Report Generation

=== Starting Tasks ===
[Executor] Task #1 is now running...
[Executor] Task #2 is now running...

=== Completing / Failing Tasks ===
[Reporter] Task #1 completed with result: 5000 rows imported successfully
[Cleaner] Releasing resources for task #1
[Alerter] Task #2 failed: PDF renderer service unavailable

=== Stats ===
{ total: 2, pending: 0, running: 0, completed: 1, failed: 1 }

=== Invalid Operation ===
[ERROR] Task #999 not found

❓ Perguntas Frequentes

P: Qual é a diferença entre o EventEmitter e os eventos do navegador? R: O EventEmitter do Node.js é executado de forma síncrona, com os ouvintes sendo executados na ordem em que foram registrados; os eventos DOM do navegador são assíncronos, passam pelas fases de captura e propagação e possuem uma estrutura de objeto de evento diferente da do Node.js.

P: O que acontece se você se esquecer de monitorar o evento error? R: Se nenhum monitorador do error estiver registrado quando o emit('error') for chamado, o Node.js lançará o erro como uma exceção não capturada, e o processo será encerrado imediatamente (a menos que o process.on('uncaughtException') esteja definido).

P: Qual é o número máximo de ouvintes que um evento pode ter? R: O limite padrão é 10. Ultrapassar esse limite acionará um aviso de vazamento de memória (mas não bloqueará a execução). Isso pode ser ajustado por meio de emitter.setMaxListeners(n); definir esse valor como 0 remove o limite.

P: Qual é o valor de retorno de emit()? R: Se o evento tiver pelo menos um ouvinte, ele retorna true; se não tiver ouvintes, retorna false. Isso pode ser usado para determinar se o evento foi processado.

P: Como posso garantir que um ouvinte seja removido automaticamente após ser acionado apenas uma vez? R: Use o método once() para registrar o ouvinte; ele será removido automaticamente após ser acionado uma vez. Isso é adequado para cenários como inicialização e sinais únicos.

P: Qual é a diferença entre off() e removeListener()? R: Eles funcionam exatamente da mesma forma. off() é um novo alias introduzido no Node.js v10 removeListener() que oferece uma sintaxe mais concisa; recomenda-se usar off() em códigos novos.

P: A que se refere this em um listener? R: Ao usar funções-seta do ES6, this herda o escopo externo; ao usar funções comuns, this se refere à instância EventEmitter, a menos que tenha sido vinculada a outro objeto por meio de bind().


📖 Resumo


📝 Exercícios

  1. Conclua todos os exemplos de código desta lição e certifique-se de que cada um deles seja executado corretamente.
  2. Modifique o exemplo completo e adicione suas próprias extensões
  3. Analise a documentação oficial, identifique 1 ou 2 APIs que não foram abordadas nesta aula e escreva um código de teste para elas.
  4. Reflexão: Como você aplicaria o que aprendeu nesta aula a um projeto do mundo real?
  5. Tente combinar o que você aprendeu nesta aula com o conteúdo das aulas anteriores para criar um pequeno projeto.
Web-Tutorial.com

Equipe Técnica Web-Tutorial

Uma plataforma de tutoriais mantida por diversos desenvolvedores. Cada tutorial é escrito e revisado por profissionais da área correspondente. Trabalhamos para manter nosso conteúdo preciso e confiável — se encontrar algum problema, avise-nos.

100%