JavaScript Avançado

Como Usar Event Loop Avançado: Microtasks, Macrotasks e requestAnimationFrame em Produção

7 min de leitura

Como Usar Event Loop Avançado: Microtasks, Macrotasks e requestAnimationFrame em Produção

O que é Event Loop e sua Estrutura Fundamental O Event Loop é o mecanismo central que permite ao JavaScript executar código assíncrono em uma linguagem single-threaded. Compreender sua estrutura é essencial para escrever código performático e previsível. O Event Loop não é parte da especificação do JavaScript em si, mas sim da implementação das engines (como V8 do Chrome), trabalhando em conjunto com as APIs fornecidas pelo ambiente (browser ou Node.js). A execução segue um ciclo: o Event Loop verifica a Call Stack, executa o código síncrono, depois processa as filas de microtasks e macrotasks. Esse processo se repete continuamente. A ordem de execução é: Call Stack → Microtasks → Rendering → Macrotasks → (volta ao início). Compreender essa sequência é crucial para prever quando seu código será executado. Microtasks vs Macrotasks: A Hierarquia de Prioridades O que são Microtasks? Microtasks têm prioridade máxima e são executadas após cada macrotask. Elas incluem: , , , e . A característica

<h2>O que é Event Loop e sua Estrutura Fundamental</h2>

<p>O Event Loop é o mecanismo central que permite ao JavaScript executar código assíncrono em uma linguagem single-threaded. Compreender sua estrutura é essencial para escrever código performático e previsível. O Event Loop não é parte da especificação do JavaScript em si, mas sim da implementação das engines (como V8 do Chrome), trabalhando em conjunto com as APIs fornecidas pelo ambiente (browser ou Node.js).</p>

<p>A execução segue um ciclo: o Event Loop verifica a Call Stack, executa o código síncrono, depois processa as filas de microtasks e macrotasks. Esse processo se repete continuamente. A ordem de execução é: <strong>Call Stack → Microtasks → Rendering → Macrotasks → (volta ao início)</strong>. Compreender essa sequência é crucial para prever quando seu código será executado.</p>

<h2>Microtasks vs Macrotasks: A Hierarquia de Prioridades</h2>

<h3>O que são Microtasks?</h3>

<p>Microtasks têm prioridade máxima e são executadas após cada macrotask. Elas incluem: <code>Promise.then()</code>, <code>Promise.catch()</code>, <code>Promise.finally()</code>, <code>MutationObserver</code> e <code>queueMicrotask()</code>. A característica distintiva é que <strong>todas as microtasks na fila são processadas antes de qualquer macrotask</strong>.</p>

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

setTimeout(() =&gt; {

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

}, 0);

Promise.resolve()

.then(() =&gt; {

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

})

.then(() =&gt; {

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

});

console.log(&#039;5. Sincronizado 2&#039;);

// Saída:

// 1. Sincronizado

// 5. Sincronizado 2

// 3. Microtask (Promise)

// 4. Microtask (Promise 2)

// 2. Macrotask (setTimeout)</code></pre>

<h3>O que são Macrotasks?</h3>

<p>Macrotasks incluem: <code>setTimeout()</code>, <code>setInterval()</code>, <code>setImmediate()</code> (Node.js), eventos DOM (<code>click</code>, <code>load</code>), e requisições HTTP. <strong>Apenas uma macrotask é executada por ciclo do Event Loop</strong>. Após cada macrotask, todas as microtasks pendentes são processadas antes de qualquer macrotask subsequente.</p>

<pre><code class="language-javascript">setTimeout(() =&gt; {

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

Promise.resolve().then(() =&gt; console.log(&#039;Microtask após Macrotask 1&#039;));

}, 0);

setTimeout(() =&gt; {

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

}, 0);

// Saída:

// Macrotask 1

// Microtask após Macrotask 1

// Macrotask 2</code></pre>

<p>Essa hierarquia existe porque Promises são fundamentais para o modelo assíncrono moderno, enquanto macrotasks são operações mais pesadas que exigem controle de quando são executadas.</p>

<h2>requestAnimationFrame: O Timing Perfeito para Animações</h2>

<h3>Onde se Encaixa no Event Loop?</h3>

<p><code>requestAnimationFrame()</code> (rAF) não é exatamente um microtask nem um macrotask. É executado <strong>entre as microtasks e a renderização</strong>, garantindo que seu código rode sincronizado com a taxa de refresh da tela (60fps ou 120fps). Isso o torna ideal para animações e manipulação do DOM.</p>

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

setTimeout(() =&gt; {

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

}, 0);

requestAnimationFrame(() =&gt; {

console.log(&#039;3. requestAnimationFrame&#039;);

});

Promise.resolve().then(() =&gt; {

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

});

console.log(&#039;5. Fim síncrono&#039;);

// Saída:

// 1. Início

// 5. Fim síncrono

// 4. Promise

// 3. requestAnimationFrame (antes da renderização)

// 2. setTimeout</code></pre>

<h3>Exemplo Prático: Animação Eficiente</h3>

<pre><code class="language-javascript">let position = 0;

function animate() {

position += 5;

const element = document.getElementById(&#039;box&#039;);

element.style.left = position + &#039;px&#039;;

if (position &lt; 300) {

requestAnimationFrame(animate);

}

}

// Usar rAF é mais eficiente que setInterval

// porque sincroniza com a renderização do navegador

requestAnimationFrame(animate);

// Evite isto:

// setInterval(() =&gt; {

// position += 5;

// element.style.left = position + &#039;px&#039;;

// }, 16); // Pode desincronizar do refresh</code></pre>

<h2>Casos Práticos: Integrando Tudo Junto</h2>

<h3>Caso 1: Carregamento de Dados com Animação</h3>

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

console.log(&#039;1. Iniciando fetch&#039;);

// Macrotask: requisição HTTP

const response = await fetch(&#039;/api/data&#039;);

// Microtask: processamento do Promise

const data = await response.json();

console.log(&#039;2. Dados recebidos&#039;);

// rAF: renderização suave

requestAnimationFrame(() =&gt; {

document.getElementById(&#039;content&#039;).innerHTML = data.message;

console.log(&#039;3. DOM atualizado&#039;);

});

}

// setTimeout garante execução assíncrona

setTimeout(() =&gt; {

fetchAndAnimate();

}, 0);</code></pre>

<h3>Caso 2: Batching de Atualizações</h3>

<pre><code class="language-javascript">const updates = [];

function scheduleUpdate(callback) {

updates.push(callback);

// Microtask: agrupa múltiplas atualizações

Promise.resolve().then(() =&gt; {

console.log(Processando ${updates.length} atualizações);

updates.forEach(cb =&gt; cb());

updates.length = 0;

});

}

// Chamadas síncronas

scheduleUpdate(() =&gt; console.log(&#039;Update 1&#039;));

scheduleUpdate(() =&gt; console.log(&#039;Update 2&#039;));

scheduleUpdate(() =&gt; console.log(&#039;Update 3&#039;));

// Saída:

// Processando 3 atualizações

// Update 1

// Update 2

// Update 3</code></pre>

<p>Esse padrão é usado internamente por frameworks como React para otimizar renderizações.</p>

<h2>Conclusão</h2>

<p>Os três conceitos principais que você deve dominar são: <strong>(1) Microtasks sempre executam antes de macrotasks</strong>, garantindo que Promises sejam processadas com alta prioridade; <strong>(2) requestAnimationFrame sincroniza seu código com a renderização do navegador</strong>, tornando-o essencial para animações e atualizações visuais eficientes; <strong>(3) Compreender essa ordem de execução permite otimizar performance</strong>, evitar race conditions e escrever código previsível. Na prática, use Promises para lógica assíncrona crítica, setTimeout para atrasar execução, e rAF para qualquer coisa visual.</p>

<h2>Referências</h2>

<ul>

<li><a href="https://developer.mozilla.org/en-US/docs/Web/API/HTML_DOM_API/Microtask" target="_blank" rel="noopener noreferrer">MDN: In depth: Microtasks and Macrotasks</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://html.spec.whatwg.org/multipage/webappapis.html#event-loop-processing-model" target="_blank" rel="noopener noreferrer">HTML Standard: Event Loop Specification</a></li>

<li><a href="https://developer.mozilla.org/en-US/docs/Web/API/window/requestAnimationFrame" target="_blank" rel="noopener noreferrer">MDN: requestAnimationFrame</a></li>

<li><a href="https://www.youtube.com/watch?v=cCOL7MC4Pl0" target="_blank" rel="noopener noreferrer">Jake Archibald: In The Loop (Video)</a></li>

</ul>

Comentários

Mais em JavaScript Avançado

Como Usar Testes de Integração em Node.js: Supertest, Banco Real e Fixtures em Produção
Como Usar Testes de Integração em Node.js: Supertest, Banco Real e Fixtures em Produção

Fundamentos de Testes de Integração em Node.js Testes de integração validam o...

Programação Funcional em JavaScript: Imutabilidade, Pureza e Composição: Do Básico ao Avançado
Programação Funcional em JavaScript: Imutabilidade, Pureza e Composição: Do Básico ao Avançado

Imutabilidade: O Fundamento da Programação Funcional A imutabilidade é o pila...

O que Todo Dev Deve Saber sobre SharedArrayBuffer e Atomics: Memória Compartilhada entre Workers
O que Todo Dev Deve Saber sobre SharedArrayBuffer e Atomics: Memória Compartilhada entre Workers

SharedArrayBuffer: O Que É e Por Que Usar SharedArrayBuffer é um objeto JavaS...