Voltar
Assincronicidade em JavaScript e o Event Loop
Como Funciona a Assincronicidade em JavaScript
JavaScript é uma linguagem síncrona e com uma única thread de execução → Isso significa que o JavaScript roda uma linha de código por vez, e só passa para a próxima quando terminar a anterior.
Imagina esse trecho de código:
const num = 3;
function multiplyBy2(inputNumber) {
const result = inputNumber * 2;
return result;
}
const output = multiplyBy2(num);
const anotherOutput = multiplyBy2(10);
Por exemplo, quando a variável output
é definida, nossa thread de execução vai rodar apenas o código do contexto gerado pela chamada da função multiplyBy2
. Só depois que essa execução termina, seguimos para a próxima linha.
JavaScript é single-threaded === uma instrução por vez
Mas o que acontece se tivermos uma linha de código lenta? E se eu quiser buscar informações de vários repositórios do GitHub e isso demorar um pouco? Nossa aplicação vai ter que esperar isso terminar pra seguir com o restante? Poderia ser… mas isso deixaria a aplicação lenta!
Até agora, com esse modelo de pensamento, temos:
- Thread de execução
- Ambiente de memória
- Call stack
Mas isso ainda não dá conta das novas situações que aparecem por aí.
Além do JavaScript: As Funcionalidades do Navegador
Pra lidar com essas situações, a gente precisa de mais do que só o JavaScript — precisamos de recursos além da linguagem! É aí que entram esses novos componentes:
- APIs do Navegador
- Promises
- Event Loop, Callback Queue e Microtask Queue
JavaScript normalmente roda dentro do navegador! E é por isso que conseguimos acessar essas funcionalidades extras por meio de algumas funções.
Funcionalidades do navegador:
- Requisições de rede – (
fetch
/xhr
) - Manipulação do DOM – (
document
) - Temporizadores – (
setTimeout
)
Algumas perguntas “simples”
Qual desses logs aparece primeiro?
function printHello() {
console.log("hi from the function");
}
setTimeout(printHello, 1000);
console.log("Hello from the global");
// Resposta: Hello from the global
E esse?
function printHello() {
console.log("hi from the function");
}
setTimeout(printHello, 0);
console.log("Hello from the global");
// Resposta: Hello from the global
Event Loop
Vamos mergulhar nesse trecho de código pra entender como o JavaScript conversa com as funcionalidades do navegador e como o event loop entra em cena :)
Como já comentamos, o JavaScript roda linha por linha. Então vamos analisar passo a passo, porque acredito que é a melhor forma de entender o que está acontecendo de verdade!
function printHello() {
console.log("Hello");
}
function blockFor1Sec() {
// Imagina aqui um loop gigante rodando por 1 segundo
}
setTimeout(printHello, 0);
blockFor1Sec();
console.log("Hi outside the function");
Passo a passo
Primeiro, declaramos a função printHello
– nada demais.
Depois, declaramos blockFor1Sec
, que vai bloquear a thread por 1 segundo com algum loop gigantesco.
Em seguida, chamamos uma funcionalidade do navegador através da função setTimeout
. Isso diz pro navegador: “depois de 0 milissegundos, execute a função printHello
”.
Detalhe importante: setTimeout
não é uma função do JavaScript – é uma Web API fornecida pelo navegador! Quando o JS encontra o setTimeout
, ele delega essa tarefa pro navegador e já segue pra próxima linha de código.
Mas… a função printHello
vai rodar logo depois? NÃO! A gente vai entender por quê daqui a pouco, mas já guarda essa informação 💝
Depois disso, chamamos blockFor1Sec
, que cria um novo contexto de execução e entra na call stack.
Quando blockFor1Sec
termina, ela sai da call stack. E agora sim vamos executar printHello
, né? NÃO! Estranho, né? Tipo… era pra acontecer… mas segura esse pensamento 💝
Aí, temos o console.log("Hi outside the function")
e SÓ DEPOIS vemos o “Hello” da função printHello
.
Alguns questionamentos que você pode ter
Você pode estar pensando:
-
Por que
printHello
não foi direto pra call stack depois dosetTimeout
? PorquesetTimeout
é uma Web API, não faz parte do JavaScript puro! Quando usamos Web APIs (comosetTimeout
,fetch
, eventos do DOM etc.), o navegador cuida delas separadamente da thread principal do JS. Quando a tarefa termina, o navegador coloca a callback (printHello
) na callback queue – e não direto na call stack. -
Então quando a gente pode tirar
printHello
da callback queue e jogar na call stack? Só quando a call stack estiver completamente vazia! O sistema fica o tempo todo perguntando:Tem alguma função na call stack?
- Sim: Continuo executando as funções dentro da call stack
- Não: Vai até a callback queue, pega a próxima função e coloca na call stack.
E esse monitoramento constante? É justamente o trabalho do event loop!
Então, O Que É o Event Loop?
O Event Loop é o “controlador de tráfego” do JavaScript, coordenando tudo isso:
- A execução síncrona do JS (a call stack)
- As APIs do navegador (setTimeout, fetch, eventos do DOM, etc.)
- A fila de callbacks (onde as funções ficam esperando a call stack esvaziar)
O que ele faz:
- Fica de olho na call stack o tempo todo
- Checa se está vazia
- Move a primeira função da callback queue pra call stack (somente quando estiver vazia)
- Repete esse processo pra sempre
Por que isso é importante? Porque o JavaScript é single-threaded, mas o navegador não é! Ele consegue lidar com várias tarefas ao mesmo tempo (timers, requisições de rede etc.) enquanto o JS vai rodando seu código. O event loop garante que, quando essas tarefas do navegador terminarem, suas callbacks sejam executadas na hora certa – ou seja, quando a thread principal estiver livre.
Simplificando: O event loop é o que permite o JavaScript ser não bloqueante mesmo sendo single-threaded. Ele faz a ponte entre o jeito síncrono do JavaScript e o mundo assíncrono das Web APIs.