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');
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
- https://jakearchibald.com/2015/tasks-microtasks-queues-and-schedules/
- https://blog.risingstack.com/node-js-at-scale-understanding-node-js-event-loop/
- https://javascript.info/microtask-queue
- https://github.com/nodejs/node/issues/22257
- https://stackoverflow.com/questions/25915634/difference-between-microtask-and-macrotask-within-an-event-loop-context
Top comments (5)
Ó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?
fala Cleiton! muito obrigado pelas palavras, eu costumo postar uma vez por semana aqui e no meu Medium (link no profile),
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:
no exemplo acima, temos um callback sendo executado dentro de uma promise, que por spec é microtask :P
o caótico mundo do JS! :D
Nice heads up.
Nice post
Muito bom!!