Entendendo Macrotarefas e Microtarefas no JavaScript
Sabe por que Promise executa antes de setTimeout(0)? Entenda como o event loop do JavaScript organiza macrotarefas, microtarefas e o papel do await e queueMicrotask.
Por que isso importa?
O JavaScript é uma linguagem single-threaded — executa tudo em uma única thread, um passo de cada vez.
O event loop é o sistema responsável por organizar a ordem de execução do seu código. Compreender o que é macrotarefa e microtarefa nesse contexto é fundamental para entender por que:
- um
setTimeout(0)executa depois de umaPromiseresolvida — mesmo com delay zero; awaitnão pausa “tudo”, apenas suspende o método atual e agenda sua continuação como microtarefa.
[INSERIR LINK INTERNO PARA o post sobre Antigravity — que aborda como IAs lidam com código assíncrono]
O que é uma Macrotarefa
Uma macrotarefa é um bloco completo de execução do JavaScript.
➡️ É tudo o que o motor JavaScript processa “de uma vez só”, antes de verificar a fila de microtarefas e pegar o próximo item da fila principal.
Exemplos que criam novas macrotarefas:
- Clique do usuário
(click) setTimeout,setInterval- Conclusão de uma requisição HTTP
O que é uma Microtarefa
Uma microtarefa é uma operação que o JavaScript executa imediatamente após a macrotarefa atual terminar — antes de iniciar qualquer nova macrotarefa da fila.
São ações leves, normalmente criadas por Promises e mecanismos assíncronos internos.
Exemplos de microtarefas:
.then()e.catch()de uma PromiseawaitqueueMicrotask()
Entendendo a ordem de execução
🔹 Exemplo 1 – sem await
console.log('A'); // síncrono → parte da macrotarefa atual
setTimeout(() => console.log('B'), 0); // nova macrotarefa
Promise.resolve().then(() => console.log('C')); // microtarefa
console.log('D'); // ainda na mesma macrotarefa
Saída real:
A
D
C
B
Explicando:
AeD→ executam imediatamente (síncrono, mesma macrotarefa)C→ é uma microtarefa, roda logo após o código síncrono terminarB→ é nova macrotarefa, roda depois que todas as microtarefas acabam
🔹 Exemplo 2 – com await
async function exemplo() {
console.log('1'); // síncrono (mesma macrotarefa)
await Promise.resolve(); // pausa aqui → cria microtarefa
console.log('2'); // volta aqui numa microtarefa
}
exemplo();
setTimeout(() => console.log('3'), 0); // nova macrotarefa
console.log('4'); // síncrono (mesma macrotarefa)
Saída real:
1
4
2
3
Explicando:
1e4→ são parte da mesma macrotarefa (síncrono)- O
awaitpausa o método e agenda a continuação (2) como microtarefa 3→ é uma nova macrotarefa (vem dosetTimeout)
Além de usar Promise.resolve().then(...), o JavaScript também oferece uma API própria para criar microtarefas:
queueMicrotask(() => {
console.log('microtask');
});
O que o queueMicrotask faz?
- Agenda a função na fila de microtarefas
- Executa logo após o código síncrono da macrotarefa atual
- Executa antes de qualquer nova macrotarefa (
setTimeout, eventos, etc.)
O comportamento é o mesmo de um .then() de Promise.
Então por que usar queueMicrotask?
Porque ele é:
| Vantagem | Por quê |
|---|---|
| 🎯 Semântico | Deixa claro que a intenção é criar uma microtarefa |
| 🧼 Mais direto | Não cria uma Promise desnecessária |
| ⚠️ Mais seguro | Erros não viram unhandled promise rejection |
Exemplo equivalente:
// Microtask usando Promise
Promise.resolve().then(() => console.log('A'));
// Microtask explícita
queueMicrotask(() => console.log('A'));
Ambos rodam no mesmo momento do event loop.
Quando preferir queueMicrotask
Use queueMicrotask quando você quer:
- Garantir execução logo após o código atual
- Manter a ordem correta sem atrasos artificiais
- Evitar o uso de
setTimeout(0)apenas para “organizar” a execução
Em código moderno e orientado a performance, queueMicrotask costuma ser a opção mais semântica e previsível.
Resumo rápido
| Tipo | Exemplo | Quando executa |
|---|---|---|
| Macrotarefa | setTimeout, setInterval, eventos (click, load), fetch concluído | Cada rodada do event loop |
| Microtarefa | Promise.then, await, queueMicrotask | Logo depois do código síncrono da macrotarefa atual |
Dica prática pra lembrar
Macrotarefa: “Algo externo que o JavaScript espera (evento, timer, rede)”
Microtarefa: “Coisas internas que precisam terminar antes de seguir (Promises, awaits)“
Conclusão
| Situação | Melhor opção | Motivo |
|---|---|---|
| Garantir execução logo depois do código atual | ✅ queueMicrotask / Promise.resolve().then(...) | É microtarefa: roda sem atraso e mantém ordem |
| Deixar o navegador respirar/pintar antes | 🕒 setTimeout(..., 0) | Cria nova macrotarefa, permite repaint |
| Evitar travar a UI com loops grandes | 🧩 setTimeout fatiando tarefas | Entrega o controle de volta ao event loop |
Se a mesma ordem é alcançada com Promise ou setTimeout(0), prefira Promise/microtarefa — é semanticamente correto, mais previsível e mais performático no event loop do JavaScript.