DEV Community

Cover image for JavaScript: Microtasks e Macrotasks
Eduardo Rabelo
Eduardo Rabelo

Posted on • Updated on

JavaScript: Microtasks e Macrotasks

Duas histórias no mesmo Event Loop e suas prioridades

Dentro do Event Loop do JavaScript/Node.js, existem dois tipos de tarefas com prioridades bem diferentes, por exemplo:

  • Microtasks: process.nextTick, Promises, Object.observe, MutationObserver
  • Macrotasks: setTimeout, setInterval, setImmediate, requestAnimationFrame, I/O, UI rendering

Mas qual a diferença prática entre os dois? Podemos resumir na seguinte afirmação:

Se alguma Microtask estiver pendente na fila para o Event Loop, ela será executada antes do início do próximo loop (no final do loop atual). Já as Macrotask serão executadas apenas no próximo loop.

Essa definição é importante, pois o resultado de algumas operações podem surpreender os não familiarizados com a engine do JavaScript.

Com isso em mente, qual será o resultado do trecho de código abaixo?

console.log('01-Console');

setTimeout(_ => console.log('02-Timeout'), 0);

Promise.resolve().then(_ => console.log('03-Promise'));

console.log('04-Console');
Enter fullscreen mode Exit fullscreen mode

Antes de olhar a resposta abaixo, você consegue imaginar a saída desse programa?


Uma hora ou outra precisamos saber a resposta…

Ao executar o trecho acima, teremos o seguinte resultado:

$ node tasks.js

01-Console
04-Console
03-Promise
02-Timeout
Enter fullscreen mode Exit fullscreen mode

Colocando algumas anotações no código, temos:

console.log('01-Console'); // [A]

setTimeout(_ => console.log('02-Timeout'), 0); // [B]

Promise.resolve().then(_ => console.log('03-Promise')); // [C]

console.log('04-Console'); // [D]
Enter fullscreen mode Exit fullscreen mode
  • [A]: Executado diretamente na “main thread”, síncrono
  • [B]: Enfileirado como uma tarefa futura, prioridade “macrotask”, será executado apenas no próximo loop
  • [C]: Enfileirado como uma tarefa futura, prioridade “microtask”, será executado imediatamente após todas as tarefas/tasks do loop atual e antes do próximo loop
  • [D]: Executado diretamente na “main thread”, síncrono

📚 Links Relacionados

Top comments (5)

Collapse
 
cleiton55048426 profile image
Cleiton

Ótimo post Eduardo. Muito bom poder encontrar conteúdo de qualidade e em português aqui no dev.

Sendo o callback uma forma de ancestral das promisses, ele se encaixaria como uma microtask, certo?

Collapse
 
oieduardorabelo profile image
Eduardo Rabelo

fala Cleiton! muito obrigado pelas palavras, eu costumo postar uma vez por semana aqui e no meu Medium (link no profile),

Sendo o callback uma forma de ancestral das promisses, ele se encaixaria como uma microtask, certo?

se usarmos ES5 como a "forma ancestral", nós não tínhamos o objeto "Promise" naquele tempo, boa parte de toda tarefa tardia de bibliotecas como jQuery, Angular 1, Backbone, etc, usavam alguma implementação com setTimeout/setInterval ou alguma outra mágica. Isso significa que se encaixam na categoria de Macrotask.

agora, você precisa entender/olhar a implementação do callback, pois o seguinte é válido:

function fazAlgo(callback) {
fetch('https://jsonplaceholder.typicode.com/todos/1')
  .then(response => response.json())
  .then(json => callback(json))
}

fazAlgo(json => {
  // isso é um callback rodando em microtask
})

no exemplo acima, temos um callback sendo executado dentro de uma promise, que por spec é microtask :P

o caótico mundo do JS! :D

Collapse
 
alexparra profile image
Alex Parra

Nice heads up.

Collapse
 
gustavolopes95 profile image
GustavoLopes95

Nice post

Collapse
 
marcos1305 profile image
Marcos Vinicius

Muito bom!!