Médio JavaScript
Prever a ordem com async/await e setTimeout
Enunciado
Dado o código abaixo, qual será a ordem de impressão? Escreva a saída exata e explique por que essa ordem ocorre. Depois, modifique o código para que a saída seja: 1, 2, 3, 4 (sem alterar a ordem dos console.log originais).
console.log(1);
setTimeout(() => console.log(2), 0);
Promise.resolve().then(() => console.log(3));
console.log(4);
Requisitos
- A saída original deve ser: 1, 4, 3, 2
- Explicar a ordem com base no event loop
- Modificar o código para que a saída seja: 1, 2, 3, 4
- A modificação não pode alterar a ordem dos
console.logoriginais (pode adicionar código em volta)
Código inicial
// Código original
console.log(1);
setTimeout(() => console.log(2), 0);
Promise.resolve().then(() => console.log(3));
console.log(4);
// Modifique abaixo para obter 1, 2, 3, 4
Saída esperada
1
4
3
2
Ver dica
Para forçar a ordem 1, 2, 3, 4, você pode aninhar as chamadas dentro de callbacks ou usar await para sequenciar.
Mostrar solução
Saída original: 1, 4, 3, 2
Explicação:
console.log(1)econsole.log(4)são síncronos e executam primeiro.Promise.thenagenda microtarefa, que roda antes de macrotarefas.setTimeoutagenda macrotarefa, que roda por último.
Código modificado para 1, 2, 3, 4:
// Modificação: aninhar os callbacks para forçar a ordem
console.log(1);
setTimeout(() => {
console.log(2);
Promise.resolve().then(() => {
console.log(3);
console.log(4);
});
}, 0);
Passo a passo
- O código original imprime 1 e 4 sincronamente.
- A microtarefa (Promise) imprime 3 antes da macrotarefa (setTimeout) que imprime 2.
- Para forçar 1, 2, 3, 4, colocamos o
console.log(2)dentro dosetTimeout. - Dentro do
setTimeout, após imprimir 2, agendamos uma microtarefa comPromise.resolve().then. - Essa microtarefa imprime 3 e, em seguida, imprime 4.
- Assim, a ordem final é 1 (síncrono), 2 (macrotarefa), 3 e 4 (microtarefa dentro da macrotarefa).
Por que funciona
Ao aninhar as chamadas, controlamos a ordem de execução. O setTimeout é executado após as microtarefas iniciais, mas como não há microtarefas pendentes no momento, ele executa 2. Dentro dele, agendamos uma microtarefa que executa 3 e 4 imediatamente após, pois microtarefas têm prioridade.
Erros comuns
- Tentar usar
awaitfora de função async: Causa erro de sintaxe. - Esquecer que
setTimeouté macrotarefa: Achar que ele executa antes de Promises. - Modificar a ordem dos
console.logoriginais: O enunciado proíbe, então é preciso reorganizar o fluxo com callbacks.
Outra forma de resolver
Usar async/await para sequenciar:
async function executar() {
console.log(1);
await new Promise(resolve => setTimeout(resolve, 0));
console.log(2);
await Promise.resolve();
console.log(3);
console.log(4);
}
executar();
Essa abordagem é mais legível para sequências assíncronas complexas.
Saída esperada
1
4
3
2