Node.js: Programação Orientada a Eventos na Prática
Se você já escreveu um servidor com Node.js e ficou na dúvida de por que o código não trava enquanto espera requisições, a resposta está em como o Node.js foi construído desde o início: tudo gira em torno de eventos. A programação orientada a eventos é o coração do Node.js — e entender esse modelo muda completamente como você escreve código para o backend. Aqui no @CanalQb, validamos cada exemplo abaixo localmente antes de publicar. Nada de teoria solta.
Por que a Programação Orientada a Eventos é tão poderosa no Node.js?
A resposta curta: porque ela elimina o maior gargalo do backend tradicional — a espera bloqueante. Em vez de criar uma thread nova para cada requisição (o que consome memória de forma agressiva), o Node.js usa um único processo que reage a eventos conforme eles chegam. O resultado prático é um servidor capaz de atender milhares de conexões simultâneas com consumo de recursos mínimo.
Execução não bloqueante
O Node.js não para e espera uma operação terminar antes de atender a próxima. Enquanto o servidor aguarda a resposta de um banco de dados, ele já está processando outra requisição. É isso que permite milhares de conexões simultâneas em um único processo sem travar.
Event Loop eficiente
O Event Loop é o mecanismo que orquestra tudo. Ele monitora uma fila de eventos continuamente e despacha callbacks na ordem certa — sem criar uma thread nova por conexão, o que tornaria qualquer servidor pesado em escala.
EventEmitter nativo
O módulo events nativo fornece o EventEmitter, base de
quase tudo na plataforma — streams, HTTP, sockets e filesystem. Você pode criar
seus próprios emissores de evento com menos de 10 linhas de código.
Ideal para APIs e tempo real
WebSockets, chats, notificações em tempo real, dashboards ao vivo — todos são casos de uso naturais para o Node.js. O modelo orientado a eventos elimina a latência desnecessária de um modelo thread-per-request.
Código mais organizado com listeners
Em vez de misturar lógica de I/O com lógica de negócio, você registra ouvintes para eventos específicos. Cada função responde a um evento e faz só o que precisa — sem efeitos colaterais inesperados e sem acoplamento desnecessário.
Integração com qualquer framework Node.js
Express, Fastify, Socket.io — todos foram construídos em cima do
EventEmitter. Dominar eventos não é opcional: é o pré-requisito real
para entender o que qualquer framework Node.js está fazendo por baixo dos panos.
Como a programação orientada a eventos funciona no Node.js?
O mecanismo é simples, mas poderoso: você registra uma função para ser executada quando um evento acontecer. O Node.js cuida de chamar essa função no momento certo, sem bloquear o processo principal. Veja o ciclo completo:
O servidor registra um "ouvinte" para o evento
Com server.on('request', callback), você instrui o Node.js a executar
aquela função toda vez que o evento request disparar. O registro acontece
uma única vez na inicialização, mas o callback pode ser chamado infinitas vezes — uma
por requisição recebida.
O Event Loop monitora e despacha eventos
O Event Loop roda em background continuamente. Quando uma requisição HTTP chega na porta configurada (ex: 3000), o sistema operacional notifica o Node.js, que empurra o evento para a fila. O Event Loop retira o evento da fila e chama o callback registrado — tudo isso sem bloquear o processo principal.
O callback processa a requisição e envia a resposta
Dentro do callback, você acessa req (requisição — URL, headers, body,
método HTTP) e res (resposta — com métodos para escrever cabeçalho e
corpo). O res.end() encerra a resposta e sinaliza ao cliente que
recebeu tudo.
Para quem é este tutorial?
Este conteúdo foi escrito para quem já sabe o básico de JavaScript e quer entender como o Node.js realmente funciona por baixo dos panos — não apenas usar frameworks sem saber o que está acontecendo.
Iniciantes em Node.js
Acabou de instalar o Node.js e quer entender o que acontece nos bastidores? Este é o ponto de partida certo — sem abstrações desnecessárias.
Devs vindos de outras linguagens
Programadores de PHP, Python ou Java que querem entender por que o Node.js lida com I/O de forma tão diferente — e por que isso importa em escala.
Quem quer construir APIs rápidas
Se seu objetivo é criar APIs REST ou serviços de backend eficientes, este é o fundamento que você precisa antes de partir para Express ou Fastify.
Interessados em tempo real
Chats, notificações push, dashboards ao vivo — qualquer sistema que precise de comunicação em tempo real se beneficia diretamente deste conhecimento.
Tutorial passo a passo: criando seu primeiro servidor orientado a eventos
No post anterior sobre Node.js e a abordagem não obstrutiva, vimos como o Node.js lida com operações de I/O sem travar o processo. Agora vamos um passo adiante: entender o mecanismo de eventos que está por trás disso, com código que os leitores do canalqb.com.br podem rodar localmente agora mesmo.
Pré-requisitos
Você precisa ter o Node.js instalado. Qualquer versão LTS recente (18.x, 20.x ou superior) funciona. Para verificar:
node --version # Deve retornar algo como: v20.12.0
O script completo do servidor HTTP orientado a eventos
Crie um arquivo chamado servidor.js. Esse é o mesmo código testado aqui no
@CanalQb antes de publicar — validado em Node.js v20.x no Linux e Windows:
// Importa o módulo HTTP nativo do Node.js
var http = require('http');
// Cria a instância do servidor sem callback direto
// (motivo explicado na nota abaixo)
var server = http.createServer();
// Registra o ouvinte para o evento 'request'
// Esse callback será chamado a cada requisição recebida
server.on('request', function(req, res) {
// Define status HTTP e tipo de conteúdo da resposta
res.writeHead(200, { 'Content-Type': 'text/html; charset=utf-8' });
// Encerra a resposta enviando um HTML simples ao cliente
res.end('<h2>Olá Mundo!</h2>');
});
// Inicia o servidor na porta 3000
server.listen(3000);
console.log('Servidor iniciado em localhost:3000. Pressione Ctrl+C para encerrar...');
server.on() em vez de passar o callback direto para createServer()?
São equivalentes na prática, mas o server.on() deixa o objeto server
acessível para adicionar outros listeners ('error', 'close') e para
chamar server.close() quando precisar encerrar o servidor de forma controlada —
algo essencial em ambientes de produção.
Rodando o servidor
No terminal, dentro da pasta onde você salvou o arquivo:
node servidor.js # Saída esperada: # Servidor iniciado em localhost:3000. Pressione Ctrl+C para encerrar...
Abra o navegador e acesse http://localhost:3000. Você vai ver "Olá Mundo!"
na tela. Cada vez que você recarregar a página, um evento request é emitido e
o callback é executado novamente — sem reiniciar o processo.
Dissecando o server.on()
O método on() vem diretamente do
EventEmitter,
a classe base que o objeto server herda. Sua assinatura:
emitter.on(nomeDoEvento, callbackFunction);
// nomeDoEvento: string que identifica o evento ('request', 'error', 'close', etc.)
// callbackFunction: função executada toda vez que o evento for emitido
Você pode registrar múltiplos listeners para o mesmo evento. O Node.js chama todos eles na ordem em que foram registrados:
server.on('request', function logRequisicao(req, res) {
console.log('[' + new Date().toISOString() + '] ' + req.method + ' ' + req.url);
});
server.on('request', function enviarResposta(req, res) {
res.writeHead(200, { 'Content-Type': 'text/html; charset=utf-8' });
res.end('<h2>Requisição registrada e respondida!</h2>');
});
emitter.setMaxListeners(n) com consciência
e documente o motivo no código.
Criando seu próprio EventEmitter — além do servidor HTTP
O servidor HTTP é só um emitter nativo. Aqui no @CanalQb, usamos emitters personalizados
em scripts de monitoramento para desacoplar alertas da lógica principal. Este script foi
otimizado para os leitores do canalqb.com.br — o detalhe do new Date().toISOString()
nos logs é um insight que a maioria dos tutoriais ignora mas que facilita muito o debug em produção:
const EventEmitter = require('events');
// Cria um emissor personalizado para monitoramento
const monitor = new EventEmitter();
// Listener para alertas normais
monitor.on('alerta', function(mensagem) {
console.log('[ALERTA] ' + new Date().toISOString() + ' — ' + mensagem);
});
// Listener para erros críticos
monitor.on('erro-critico', function(mensagem) {
console.error('[ERRO CRÍTICO] ' + new Date().toISOString() + ' — ' + mensagem);
// Aqui você pode acionar webhook, email ou Telegram Bot
});
// Simulando emissão de eventos em intervalos
setTimeout(function() {
monitor.emit('alerta', 'Uso de CPU acima de 80%');
}, 1000);
setTimeout(function() {
monitor.emit('erro-critico', 'Conexão com o banco de dados perdida');
}, 3000);
O padrão acima é útil para desacoplar partes do sistema. O emissor não sabe quem vai escutar — só emite o evento certo no momento certo. Os ouvintes cuidam do resto. Em projetos maiores, esse desacoplamento é o que permite adicionar novos comportamentos (ex: enviar alerta para Telegram) sem tocar no código que detecta o problema.
Entendendo o Event Loop — o motor invisível
Para entender por que tudo isso funciona, vale ter noção básica do Event Loop. Ele é uma fila de execução que roda em ciclos:
/*
Ciclo do Event Loop (simplificado):
1. timers — setTimeout() e setInterval() prontos para executar
2. I/O callbacks — callbacks de I/O (rede, filesystem) pendentes
3. idle/prepare — uso interno do Node.js
4. poll — busca novos eventos de I/O
(fica "esperando" aqui se a fila estiver vazia)
5. check — setImmediate() executa aqui
6. close callbacks — eventos de fechamento (socket.on('close', ...))
O Node.js percorre esses estágios continuamente enquanto o processo está ativo.
Quando a fila de eventos está vazia e não há mais callbacks pendentes,
o processo encerra automaticamente.
*/
O insight que a maioria dos tutoriais não explica: na fase poll, quando
não há eventos pendentes, o Node.js literalmente para de consumir CPU e fica bloqueado
aguardando o sistema operacional notificar uma nova chegada. É por isso que um servidor
Node.js ocioso consome quase zero de CPU — diferente de um loop while(true)
que queimaria 100% de um núcleo.
Recursos e documentação oficial para aprofundar
📚 Documentação oficial — Events
Referência completa da classe EventEmitter, com todos os métodos, eventos e exemplos oficiais.
→ nodejs.org/api/events🔄 Guia oficial — Event Loop
Explicação detalhada de como o Event Loop, timers e process.nextTick funcionam internamente.
→ nodejs.org/en/docs/guides🌐 Documentação — HTTP Module
Todos os eventos, métodos e propriedades do módulo HTTP nativo do Node.js.
→ nodejs.org/api/http📖 Post anterior — Abordagem Não Obstrutiva
Entenda como o Node.js evita o bloqueio de execução e por que isso muda tudo no backend.
→ Ver no @CanalQb

Comentários
Comente só assim vamos crescer juntos!