DEV Community

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

Posted on

JavaScript: Microtasks e Macrotasks

Duas histórias no mesmo Event Loop e suas prioridades

Dentro do Event Loop do JavaScript, 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');

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

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]
  • [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

Discussion (5)

Collapse
alexparra profile image
Alex Parra

Nice heads up.

Collapse
gustavolopes95 profile image
GustavoLopes95

Nice post

Collapse
marcos1305 profile image
Marcos Vinicius

Muito bom!!

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 Author

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