Pular para o conteudo principal

Event Loop de Verdade no Browser

Como entender a ordem real entre código síncrono, microtasks, timers, eventos e renderização sem misturar tudo numa fila imaginaria só.

Andrews Ribeiro

Andrews Ribeiro

Founder & Engineer

O problema

Muita explicação sobre event loop para cedo demais na história.

Ela mostra:

  • call stack
  • microtask queue
  • macrotask queue

E pronto.

Só que no browser o problema real quase nunca e só prever a ordem entre dois console.log.

O problema real e este:

  • por que o clique demorou a responder?
  • por que o setTimeout atrasou?
  • por que eu mudei o DOM e a tela ainda não pintou?

Modelo mental

No browser, o event loop coordena a thread principal entre quatro tipos de pressao:

  • código síncrono rodando agora
  • microtasks pendentes
  • tasks como timer e eventos
  • oportunidade de renderização

Se quiser uma frase simples:

enquanto a thread principal esta ocupada demais, o browser não consegue te obedecer direito.

Isso vale para:

  • executar JS
  • responder input
  • processar timer
  • atualizar a tela

Quebrando o problema

Código síncrono segura tudo

Enquanto um bloco síncrono esta rodando, nada entra no meio.

Se você faz trabalho pesado ali:

  • clique espera
  • timer espera
  • renderização espera

O browser não esta ignorando você.

Ele esta ocupado.

Microtasks vem antes da proxima task

Depois que o código atual termina, o ambiente esvazia microtasks pendentes.

Aqui entram coisas como:

  • Promise.then
  • catch
  • finally
  • continuacao de await

Por isso Promise.then costuma aparecer antes de setTimeout(..., 0).

Não e porque promise e “mais rápida”.

E porque a prioridade da fila e diferente.

Timers e eventos esperam a vez deles

setTimeout(..., 0) não significa “agora”.

Significa só que aquela task ficou elegivel cedo.

Ela ainda precisa esperar:

  • o código síncrono atual acabar
  • as microtasks pendentes esvaziarem

O mesmo vale para muita coisa ligada a evento e callbacks do ambiente.

Renderização também precisa de janela

Esse ponto costuma limpar bastante a confusao de frontend.

Você pode mudar o DOM agora, mas a pintura na tela depende de o browser conseguir chegar na etapa de renderização.

Se você faz isto:

  1. muda o estado
  2. muda o DOM
  3. roda um bloco pesado logo em seguida

a tela pode parecer “atrasada” porque a thread principal não liberou espaco para o browser pintar.

Exemplo simples

Olhe este fluxo:

button.addEventListener('click', async () => {
  box.textContent = 'Carregando...'

  await Promise.resolve()

  console.log('microtask')

  const start = Date.now()
  while (Date.now() - start < 200) {}

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

O que costuma acontecer:

  • o click agenda o handler
  • o texto muda no DOM
  • a continuacao do await entra como microtask
  • o bloco pesado prende a thread
  • o timer fica esperando
  • a pintura também pode ficar esperando

Ou seja:

você mudou o DOM cedo, mas ainda assim a interface pode não parecer responsiva imediatamente.

Isso confunde porque muita gente pensa que “mexer no DOM” e igual a “ver na tela”.

Não e.

Erros comuns

  • Achar que setTimeout(..., 0) significa execução imediata.
  • Dizer que promise e mais rápida em vez de explicar prioridade.
  • Esquecer que microtasks demais também atrasam a vida do browser.
  • Tratar renderização como se acontecesse automaticamente no mesmo instante da mudança.
  • Ignorar que thread principal compartilha JS, input e pintura.

Como um senior pensa

Quem tem mais experiência costuma olhar para UI travando e pensar:

“O que esta monopolizando a thread principal? Trabalho síncrono? Microtasks demais? Renderização sem janela?”

Essa pergunta e muito mais útil do que ficar repetindo nomes de fila.

Porque leva para ação real:

  • quebrar trabalho pesado
  • adiar parte do processamento
  • mover trabalho para outro lugar
  • reduzir bloqueio antes da pintura

O que o entrevistador quer ver

Em entrevista, event loop no browser costuma separar bem quem decorou termo de quem consegue depurar interface de verdade.

O avaliador quer ver se você:

  • explica a ordem de execução com clareza
  • conecta microtask e timer sem supersticao
  • menciona thread principal e renderização
  • relaciona isso a input lag e jank

Uma resposta forte costuma soar assim:

“No browser, o event loop não decide só a ordem do JavaScript. Ele também afeta quando eventos entram e quando a tela consegue pintar. Se eu prendo a thread principal, atraso timer, input e renderização ao mesmo tempo.”

Event loop entendido pela metade explica console.log. Entendido direito explica interface travando.

Resumo rápido

O que vale manter na cabeça

Checklist de pratica

Use isto ao responder

Você concluiu este artigo

Próximo artigo DNS, TCP, TLS e HTTP na prática Artigo anterior O Custo Real de JavaScript no Frontend

Continue explorando

Artigos relacionados