JavaScript

Event Loop em JavaScript: Call Stack, Task Queue e Microtasks na Prática

5 min de leitura

Event Loop em JavaScript: Call Stack, Task Queue e Microtasks na Prática

Call Stack: O Coração da Execução O Call Stack é uma estrutura de dados que rastreia a ordem de execução das funções em JavaScript. Quando uma função é chamada, ela é adicionada ao topo da pilha; quando retorna, é removida. JavaScript é single-threaded, portanto existe apenas um Call Stack por contexto de execução. Neste exemplo, é inserida no stack, então é inserida acima dela. conclui e é removida, permitindo que finalize. Entender isso é fundamental: operações síncronas preenchem o stack sequencialmente, e operações assíncronas não blocam esse processo porque saem do stack imediatamente. Task Queue e Microtask Queue: A Fila de Espera Quando operações assíncronas (como , , ou promises) são executadas, elas não ficam no Call Stack. Em vez disso, suas callbacks são colocadas em filas: a Task Queue (ou Callback Queue) para tarefas como , e a Microtask Queue para promises e . A ordem ocorre porque todas as microtasks (promises) são executadas antes de qualquer task da

<h2>Call Stack: O Coração da Execução</h2>

<p>O Call Stack é uma estrutura de dados que rastreia a ordem de execução das funções em JavaScript. Quando uma função é chamada, ela é adicionada ao topo da pilha; quando retorna, é removida. JavaScript é single-threaded, portanto existe apenas um Call Stack por contexto de execução.</p>

<pre><code class="language-javascript">function primeira() {

segunda();

console.log(&#039;Primeira&#039;);

}

function segunda() {

console.log(&#039;Segunda&#039;);

}

primeira();

// Saída: Segunda, Primeira</code></pre>

<p>Neste exemplo, <code>primeira()</code> é inserida no stack, então <code>segunda()</code> é inserida acima dela. <code>segunda()</code> conclui e é removida, permitindo que <code>primeira()</code> finalize. Entender isso é fundamental: operações síncronas preenchem o stack sequencialmente, e operações assíncronas não blocam esse processo porque saem do stack imediatamente.</p>

<h2>Task Queue e Microtask Queue: A Fila de Espera</h2>

<p>Quando operações assíncronas (como <code>setTimeout</code>, <code>fetch</code>, ou promises) são executadas, elas não ficam no Call Stack. Em vez disso, suas callbacks são colocadas em filas: a <strong>Task Queue</strong> (ou Callback Queue) para tarefas como <code>setTimeout</code>, e a <strong>Microtask Queue</strong> para promises e <code>MutationObserver</code>.</p>

<pre><code class="language-javascript">console.log(&#039;Início&#039;);

setTimeout(() =&gt; {

console.log(&#039;setTimeout&#039;);

}, 0);

Promise.resolve()

.then(() =&gt; {

console.log(&#039;Promise&#039;);

});

console.log(&#039;Fim&#039;);

// Saída: Início, Fim, Promise, setTimeout</code></pre>

<p>A ordem ocorre porque todas as microtasks (promises) são executadas antes de qualquer task da Task Queue. Mesmo com <code>setTimeout</code> de 0ms, a promise é processada primeiro. Isso é crítico em aplicações reais onde você precisa garantir que certos códigos executem na sequência correta.</p>

<h2>Event Loop: O Maestro da Orquestração</h2>

<p>O Event Loop é o mecanismo que coordena Call Stack, Microtask Queue e Task Queue. Seu funcionamento segue este algoritmo: (1) Execute tudo no Call Stack até esvaziar; (2) Execute todas as microtasks pendentes; (3) Execute uma task da Task Queue; (4) Repita.</p>

<pre><code class="language-javascript">console.log(&#039;Script inicia&#039;);

setTimeout(() =&gt; {

console.log(&#039;Task 1: setTimeout&#039;);

Promise.resolve().then(() =&gt; console.log(&#039;Microtask dentro de Task 1&#039;));

}, 0);

Promise.resolve()

.then(() =&gt; {

console.log(&#039;Microtask 1&#039;);

setTimeout(() =&gt; console.log(&#039;Task 2: setTimeout dentro de promise&#039;), 0);

})

.then(() =&gt; {

console.log(&#039;Microtask 2&#039;);

});

console.log(&#039;Script termina&#039;);

/* Saída:

Script inicia

Script termina

Microtask 1

Microtask 2

Task 1: setTimeout

Microtask dentro de Task 1

Task 2: setTimeout dentro de promise

*/</code></pre>

<p>Este exemplo demonstra a precedência: código síncrono, depois todas as microtasks, depois uma task, e o ciclo continua. Quando você coloca um <code>setTimeout</code> dentro de uma promise, esse <code>setTimeout</code> entra em uma nova Task Queue, processado apenas após todas as microtasks atuais.</p>

<h3>Aplicação Prática: Evitando Comportamentos Inesperados</h3>

<pre><code class="language-javascript"></code></pre>

<p>Em aplicações reais, você frequentemente enfrenta cenários onde precisa sincronizar operações de rede, atualização de DOM e lógica de negócio. Usar promises para operações que devem ser atômicas e <code>setTimeout</code> para operações que podem ser diferidas evita race conditions e bugs sutis.</p>

<h2>Conclusão</h2>

<p>Os três pilares do Event Loop em JavaScript são: o <strong>Call Stack</strong> gerencia a execução síncrona em ordem LIFO; a <strong>Microtask Queue</strong> processa promises e operações críticas com alta prioridade; a <strong>Task Queue</strong> armazena callbacks de operações assíncronas como <code>setTimeout</code>. O <strong>Event Loop</strong> orquestra tudo isso, garantindo que o stack esvazie, depois as microtasks, e então uma task por ciclo. Dominar esses conceitos é essencial para escrever código assíncrono previsível e eliminar bugs relacionados a timing que consomem horas de debugging.</p>

<h2>Referências</h2>

<ul>

<li><a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Event_loop" target="_blank" rel="noopener noreferrer">MDN Web Docs - Event Loop</a></li>

<li><a href="https://javascript.info/event-loop" target="_blank" rel="noopener noreferrer">JavaScript.info - Event Loop</a></li>

<li><a href="https://www.youtube.com/watch?v=8aGhZQkoFbQ" target="_blank" rel="noopener noreferrer">Phil Roberts - What the heck is the event loop anyway? (Vídeo)</a></li>

<li><a href="https://eloquentjavascript.net/11_async.html" target="_blank" rel="noopener noreferrer">Eloquent JavaScript - Asynchronous Programming</a></li>

<li><a href="https://tc39.es/ecma262/#sec-jobs-and-job-queues" target="_blank" rel="noopener noreferrer">TC39 - ECMAScript Specification (Promise e Microtasks)</a></li>

</ul>

Comentários

Mais em JavaScript

Como Usar Novidades do ECMAScript: ES2022, ES2023 e ES2024 na Prática em Produção
Como Usar Novidades do ECMAScript: ES2022, ES2023 e ES2024 na Prática em Produção

ES2022: Top-Level Await e Class Fields O ES2022 trouxe melhorias significativ...

Desestruturação, Spread e Rest em Objetos JavaScript: Do Básico ao Avançado
Desestruturação, Spread e Rest em Objetos JavaScript: Do Básico ao Avançado

Desestruturação em Objetos JavaScript A desestruturação é uma sintaxe moderna...

NPM e Package.json: Gerenciamento de Dependências em JavaScript na Prática
NPM e Package.json: Gerenciamento de Dependências em JavaScript na Prática

O que é NPM e por que você precisa dominar NPM (Node Package Manager) é o ger...