This content originally appeared on DEV Community and was authored by João Victor
O Event Loop é o mecanismo responsável por decidir quando callbacks e continuidades de operações assíncronas devem ser executados. Ele não executa operações de I/O diretamente, mas organiza a ordem em que elas retornam para o JavaScript. Essa arquitetura permite que o Node.js mantenha uma única thread de execução para JavaScript, enquanto delega operações de rede, disco e sistema operacional para componentes especializados do runtime e do próprio sistema operacional.
Início
Quando iniciamos um processo Node.js, o runtime carrega o arquivo de entrada da aplicação e executa todo o código síncrono disponível na Call Stack. Somente após essa etapa o Event Loop passa a assumir o controle do fluxo da aplicação, verificando continuamente quais callbacks estão prontos para execução.
│ timers │
└─────────────┬─────────────┘
│
v
┌───────────────────────────┐
┌─>│ pending callbacks │
│ └─────────────┬─────────────┘
│ ┌─────────────┴─────────────┐
│ │ idle, prepare │
│ └─────────────┬─────────────┘ ┌───────────────┐
│ ┌─────────────┴─────────────┐ │ incoming: │
│ │ poll │<─────┤ connections, │
│ └─────────────┬─────────────┘ │ data, etc. │
│ ┌─────────────┴─────────────┐ └───────────────┘
│ │ check │
│ └─────────────┬─────────────┘
│ ┌─────────────┴─────────────┐
│ │ close callbacks │
│ └─────────────┬─────────────┘
│ ┌─────────────┴─────────────┐
└──┤ timers │
└───────────────────────────┘
Trecho retirado da documentação principal.
Sobre o Event Loop
Durante muito tempo tratei o Event Loop como um dos conceitos mais complexos do Node.js. Depois de estudar a documentação oficial com mais calma, percebi que a dificuldade não está no Event Loop em si, mas na quantidade de conceitos diferentes que normalmente são apresentados ao mesmo tempo: libuv, Call Stack, Promises, Microtasks, Sistema Operacional e I/O.
Quando isolamos o papel do Event Loop, ele se torna surpreendentemente simples.
Definindo os passos e apresentando o iceberg 🧊
O Event Loop não executa trabalho. Ele agenda trabalho.
Acredito que o principal problema para entender o Event Loop esteja na confusão entre os contextos. Em um primeiro momento, imaginamos que o Event Loop é o "MacGyver" do runtime ou algo extremamente complexo. Porém, não é.
O interessante na arquitetura do runtime é como cada parte é extremamente especializada. Quando falamos de Event Loop, estamos falando única e simplesmente sobre quando executar um callback.
Pense no seguinte: a execução do JavaScript ocorre em uma única thread. Isso significa que os comandos vão rodar de forma linear, um após o outro, obrigatoriamente. Portanto, precisamos de algum mecanismo de coordenação para que o runtime seja minimamente confiável e siga um fluxo previsível.
Outro ponto extremamente importante: quando ouvimos falar em Call Stack, Microtasks e Event Loop, devemos entender que o Event Loop não possui uma Call Stack própria. Além disso, uma microtask tem muito mais relação com a Call Stack do que com o próprio Event Loop.
Se o assunto é Event Loop, podemos defini-lo como uma lista de prioridades para callbacks de naturezas diferentes. Isso explica o que ele faz, mas não explica como.
O Event Loop é um consumidor
Imagine o seguinte: o Event Loop tem como função depositar na Call Stack todos os callbacks que estão na fila da fase atual. Pense em cada fase como uma fila e no Event Loop como um consumidor.
Ele percorre obrigatoriamente as seguintes fases:
- Timers
- Pending Callbacks
- Idle
- Prepare
- Poll
- Check
- Close Callbacks
Assim que você executa um código com Node.js, o fluxo ocorre da seguinte forma:
- O Event Loop seleciona callbacks da fase atual e os coloca na Call Stack para execução.
- A Call Stack executa um callback e, ao final da execução, drena a fila de microtasks. É aqui que entram as Promises resolvidas e as continuações geradas por async/await.
- Após limpar a fila de microtasks, o runtime avança para a próxima fase do Event Loop.
- O processo se repete até o encerramento da aplicação. Note que uma fase não possui necessariamente uma Call Stack própria. O runtime possui apenas uma Call Stack e uma fila de microtasks. As fases do Event Loop existem para determinar quais callbacks podem ser executados em cada momento.
Nem todas as fases são para você
Apesar de o diagrama do Event Loop apresentar sete fases, nem todas existem para que desenvolvedores JavaScript agendem callbacks diretamente.
Algumas fases são utilizadas internamente pela libuv para preparação e coordenação do runtime. Na prática, como desenvolvedor Node.js, você interage principalmente com Timers, Pending Callbacks, Poll, Check e Close Callbacks.
As fases Idle e Prepare, por exemplo, existem para permitir que a libuv realize atividades internas antes de entrar na fase de processamento de eventos. Embora façam parte do ciclo do Event Loop, dificilmente você terá contato direto com elas durante o desenvolvimento de aplicações.
Timers
Responsável por executar callbacks agendados por temporizadores.
Exemplos:
setTimeout(() => {
console.log('Executado após 1 segundo');
}, 1000);
setInterval(() => {
console.log('Executado periodicamente');
}, 5000);
Importante: o tempo informado representa o tempo mínimo de espera. Não existe garantia de execução exata naquele instante.
Pending Callbacks
Executa callbacks de determinadas operações que foram adiadas para a próxima iteração do Event Loop.
Essa fase é pouco utilizada diretamente por desenvolvedores, mas é frequentemente utilizada internamente pelo Node.js para reportar erros ou resultados de operações assíncronas.
Exemplo conceitual:
socket.on('error', (err) => {
console.log(err);
});
Alguns callbacks relacionados a erros de rede e TCP podem passar por essa fase antes de serem executados.
Idle e Prepare
As fases Idle e Prepare são utilizadas internamente pela libuv para coordenar o funcionamento do runtime antes da entrada na fase Poll.
Durante essas etapas, a libuv realiza verificações, preparações e atividades de manutenção necessárias para o funcionamento correto do Event Loop. Apesar de fazerem parte oficialmente do ciclo, elas não possuem APIs públicas para que desenvolvedores registrem callbacks diretamente.
Exemplos
Não existem APIs JavaScript que permitam agendar callbacks para essas fases.
// Não existe algo equivalente a isso
idle(() => {});
prepare(() => {});
Quando utilizar
Nunca diretamente.
Como desenvolvedor Node.js, você normalmente interage apenas com as fases:
- Timers
- Pending Callbacks
- Poll
- Check
- Close Callbacks #### Poll É a fase mais importante do Event Loop. Aqui a libuv verifica se existem operações de I/O concluídas e callbacks aguardando execução. Exemplos:
fs.readFile('arquivo.txt', (err, data) => {
console.log(data.toString());
});
http.createServer((req, res) => {
res.end('Olá');
});
database.query('SELECT * FROM users', callback);
Leitura de arquivos, conexões de rede, requisições HTTP e diversas operações assíncronas costumam retornar seus callbacks para esta fase.
Check
Executada logo após a fase Poll.
É a fase utilizada pelo setImmediate().
Exemplo:
setImmediate(() => {
console.log('Executado na fase Check');
});
Uma forma simples de pensar é:
- setTimeout(..., 0) → Timers
- setImmediate(...) → Check
Close Callbacks
Executa callbacks relacionados ao encerramento de recursos.
Exemplo:
socket.on('close', () => {
console.log('Conexão encerrada');
});
stream.on('close', () => {
console.log('Stream finalizada');
});
Essa fase permite que recursos sejam liberados corretamente antes do término definitivo da operação.
Conclusão
O assustador Event Loop é, na prática, apenas um coordenador das nossas invocações. Toda a parte pesada acontece entre o kernel do sistema operacional e a libuv.
This content originally appeared on DEV Community and was authored by João Victor
João Victor | Sciencx (2026-06-17T21:51:46+00:00) Event Loop – Entendendo uma das bases do Node. Retrieved from https://www.scien.cx/2026/06/17/event-loop-entendendo-uma-das-bases-do-node/
Please log in to upload a file.
There are no updates yet.
Click the Upload button above to add an update.