Event Loop no JavaScript: por que o código não roda na ordem que você escreveu
23 de março de 2026 às 19:23 - Por Larissa Santos

Você já sabe o resultado desse código abaixo? Qual a ordem que ele será executado?
console.log('1')
setTimeout(() => console.log('2'), 0)
console.log('3')
O timeout é zero milissegundos. Zero. E mesmo assim o resultado é:
1
3
2
Por que o 2 sai por último se o delay é zero?
A resposta está no Event Loop, e entender isso muda a forma como você lê e escreve JavaScript.
JavaScript é single-thread
Antes de qualquer coisa, é importante entender isso: JavaScript executa uma coisa por vez.
Não existe paralelismo real dentro do JavaScript. Há apenas uma linha de execução, chamada de thread. Isso significa que, enquanto uma função está rodando, nenhuma outra pode rodar ao mesmo tempo.
Então como o JavaScript consegue fazer coisas assíncronas, como requisições HTTP, timers e eventos de clique, sem travar tudo?
É aí que entram as peças do Event Loop.
As três peças
1. Call Stack
A Call Stack é onde o código é executado. Funciona como uma pilha: o que entra por último, sai primeiro.
Quando você chama uma função, ela entra na stack. Quando ela termina, sai da stack. Simples assim.
function soma(a, b) {
return a + b
}
function calcular() {
return soma(2, 3)
}
calcular()
A stack nesse momento ficaria assim:
[ soma ]
[ calcular ]
[ main ]
Quando soma termina, sai. Quando calcular termina, sai. Quando o script termina, sai.
2. Web APIs
Quando você chama setTimeout, fetch, ou adiciona um event listener, o browser assume o controle.
Isso é importante: essas funcionalidades não são JavaScript puro. São APIs fornecidas pelo ambiente (browser ou Node.js). O JavaScript entrega a tarefa para elas e segue em frente sem esperar.
console.log('1')
setTimeout(() => console.log('2'), 0)
console.log('3')
O que acontece aqui:
console.log('1')entra na stack, executa, saisetTimeoutentra na stack, entrega o callback para a Web API, saiconsole.log('3')entra na stack, executa, sai- A Web API termina o timer e empurra o callback para a fila
3. A Fila (Queue)
Quando uma Web API termina seu trabalho, o callback não vai direto para a stack. Ele vai para uma fila de espera.
E ele só sai dessa fila quando a stack estiver completamente vazia.
Stack: []
Queue: [ () => console.log('2') ]
Agora a stack está vazia. O Event Loop pega o callback da fila e coloca na stack. Ele executa. O 2 aparece.
O Event Loop em si
O Event Loop é o mecanismo que conecta tudo isso. Ele fica em um loop contínuo fazendo uma pergunta:
A stack está vazia? Se sim, pega o próximo item da fila.
É só isso. Simples assim na teoria, mas é o que permite que o JavaScript seja assíncrono mesmo sendo single-thread.
Visualizando o fluxo completo:
console.log('1') → Stack → executa → sai
setTimeout(fn, 0) → Stack → entrega para Web API → sai
console.log('3') → Stack → executa → sai
Web API termina → fn vai para a Queue
Event Loop verifica → Stack está vazia? Sim
→ pega fn da Queue → coloca na Stack
fn executa → console.log('2') → sai
Por que isso responde a pergunta inicial?
O timeout era zero, mas o callback só pôde entrar na stack depois que ela esvaziou. E ela só esvaziou depois que o console.log('3') executou.
Mesmo com delay zero, o callback nunca pula a fila.
Microtasks e Macrotasks
Até aqui falamos de uma única fila. Na prática, existem duas, com prioridades diferentes.
Macrotasks — setTimeout, setInterval, eventos de DOM. Essa é a fila que vimos até agora.
Microtasks — Promise.then, queueMicrotask. Essa fila tem prioridade maior.
A regra é:
Depois que a stack esvazia, o Event Loop processa todas as microtasks antes de pegar a próxima macrotask.
Veja o que acontece aqui:
console.log('1')
setTimeout(() => console.log('timeout'), 0)
Promise.resolve().then(() => console.log('promise'))
console.log('2')
Resultado:
1
2
promise
timeout
O fluxo:
console.log('1')executasetTimeoutentrega o callback para a Web APIPromise.resolve().then(...)coloca o callback na fila de microtasksconsole.log('2')executa- Stack esvazia
- Event Loop processa microtasks primeiro:
promiseaparece - Event Loop pega a próxima macrotask:
timeoutaparece
Resumo
- JavaScript é single-thread: executa uma coisa por vez
- A Call Stack é onde o código roda
- Web APIs assumem tarefas assíncronas enquanto a stack segue em frente
- Os callbacks vão para uma fila e só entram na stack quando ela estiver vazia
- O Event Loop é o mecanismo que faz essa verificação continuamente
- Microtasks (Promises) têm prioridade sobre Macrotasks (setTimeout)
Conclusão
Event Loop não é um recurso avançado reservado para casos específicos. É o modelo de execução do JavaScript, e ele está presente em cada await, cada .then e cada evento que você escuta.
Quanto mais claro estiver esse modelo na sua cabeça, mais previsível o seu código assíncrono vai se tornar.