Voltar ao blog
event loopJavaScriptassíncronodesenvolvimento

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

Event Loop no JavaScript: por que o código não roda na ordem que você escreveu

Você já sabe o resultado desse código abaixo? Qual a ordem que ele será executado?

js
console.log('1')
setTimeout(() => console.log('2'), 0)
console.log('3')

O timeout é zero milissegundos. Zero. E mesmo assim o resultado é:

txt
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.

js
function soma(a, b) {
  return a + b
}

function calcular() {
  return soma(2, 3)
}

calcular()

A stack nesse momento ficaria assim:

txt
[ 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.

js
console.log('1')
setTimeout(() => console.log('2'), 0)
console.log('3')

O que acontece aqui:

  1. console.log('1') entra na stack, executa, sai
  2. setTimeout entra na stack, entrega o callback para a Web API, sai
  3. console.log('3') entra na stack, executa, sai
  4. 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.

txt
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:

txt
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.

MacrotaskssetTimeout, setInterval, eventos de DOM. Essa é a fila que vimos até agora.

MicrotasksPromise.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:

js
console.log('1')

setTimeout(() => console.log('timeout'), 0)

Promise.resolve().then(() => console.log('promise'))

console.log('2')

Resultado:

txt
1
2
promise
timeout

O fluxo:

  1. console.log('1') executa
  2. setTimeout entrega o callback para a Web API
  3. Promise.resolve().then(...) coloca o callback na fila de microtasks
  4. console.log('2') executa
  5. Stack esvazia
  6. Event Loop processa microtasks primeiro: promise aparece
  7. Event Loop pega a próxima macrotask: timeout aparece

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.

Feito com e Vue.js
2026 © Larissa Santos