Ao terminar esta aula, você vai conseguir
- Diferenciar resultado síncrono de assíncrono
- Ler a ordem observável de tarefas no event loop
- Usar await e try/catch com Promises
Servidores lidam com operações que demoram: consultar um banco, ler um arquivo
ou aguardar outro serviço. Assincronia permite iniciar esse trabalho e
continuar atendendo o que está disponível, em vez de manter o JavaScript parado
durante toda a espera. Uma Promise representa um resultado futuro: pendente,
concluído ou rejeitado.
Pense no painel de uma lanchonete. O atendente registra um pedido, entrega a comanda à cozinha e pode receber o próximo enquanto o primeiro é preparado. Quando a cozinha sinaliza, ele continua aquele atendimento. O limite: o event loop não é uma pessoa e não torna cálculo pesado automaticamente paralelo. Um laço enorme ainda pode ocupar a thread principal e atrasar todos os pedidos.
Leia a ordem, não apenas as linhas
Observe este arquivo:
console.log('1. abriu');
setTimeout(() => {
console.log('3. timer terminou');
}, 0);
console.log('2. continuou');Mesmo com atraso zero, a saída é 1, 2, 3. O callback do timer fica pronto
para uma etapa futura; o código síncrono da execução atual termina antes. O
event loop coordena quando callbacks e outras continuações podem voltar à
pilha de execução.
Essa ordem não significa que todo callback sempre vem por último em qualquer sistema. Node possui fases e filas específicas. Para começar, guarde a regra operacional: o código síncrono atual termina, e uma continuação assíncrona roda quando sua fila e o loop permitem.
Escreva a sequência com async e await
Uma Promise pode ser consumida com .then(), mas async/await costuma deixar a
sequência de dependências mais visível:
function buscarPedido(id) {
return new Promise((resolve, reject) => {
setTimeout(() => {
if (id <= 0) return reject(new Error('ID inválido'));
resolve({ id, status: 'recebido' });
}, 100);
});
}
async function mostrarPedido(id) {
try {
const pedido = await buscarPedido(id);
console.log(pedido);
} catch (erro) {
console.error(erro.message);
}
}
await mostrarPedido(7);Uma função async sempre devolve uma Promise. await suspende a continuação
daquela função até a Promise se resolver; ele não congela magicamente o processo
inteiro. Se a Promise for rejeitada, try/catch transforma a falha em um caminho
explícito. Rode também com -1 e confirme a mensagem ID inválido.
Concorrência quando as tarefas são independentes
Se duas operações não dependem uma da outra, esperar a primeira para só então iniciar a segunda desperdiça tempo. Inicie ambas e aguarde o conjunto:
const [cliente, pedido] = await Promise.all([
buscarCliente(3),
buscarPedido(7),
]);Promise.all rejeita se uma das Promises rejeitar. Também devolve resultados na
ordem do array fornecido, não na ordem em que terminaram. Essa distinção pode ser
comprovada no laboratório ao trocar os atrasos.
O laboratório roda timers reais do navegador, não o event loop específico do Node nem acesso a arquivos. A lógica de Promises e a ordem observável são JavaScript genuíno; as APIs ao redor mudam conforme o runtime.
Há uma distinção prática entre esperar I/O e executar cálculo. Consultar rede ou disco permite que Node aguarde o sistema operacional e retome depois. Já uma função que calcula continuamente por vários segundos ocupa a execução de JavaScript. Se um timer simples atrasar muito enquanto esse cálculo roda, você observou bloqueio da thread, não uma falha da Promise. A solução depende do caso: reduzir trabalho, dividi-lo ou usar mecanismos apropriados como workers.
Erro comum: esquecer de aguardar ou capturar
Registrar buscarPedido(7) sem await mostra uma Promise, não o pedido. Outro
erro é disparar uma Promise que pode rejeitar e nunca tratar a falha. Use await
dentro de try/catch, retorne a Promise para quem deve tratá-la ou encadeie um
.catch(). Não esconda o erro com um bloco vazio.
Na missão, meça duas esperas com console.time, primeiro em sequência e depois
com Promise.all. O teste passa quando a versão concorrente se aproxima da maior
espera, e não da soma. Na próxima aula, essa coordenação vai sustentar um servidor
HTTP que recebe requisições enquanto outras respostas ainda estão em preparo.
Laboratório ao vivo
Fila assíncrona de pedidos
O sandbox usa timers do navegador para demonstrar a ordem assíncrona. Mude os atrasos e confira que Promise.all preserva a ordem do array de resultados.
Pare e pense
O que await faz dentro de uma função async?
await pausa a continuação daquela função async. Enquanto a operação está pendente, o runtime pode atender outros trabalhos disponíveis.
Faça sem copiar
Crie duas Promises com atrasos diferentes, execute-as com Promise.all e anote início e fim. A missão passa se o tempo total ficar perto da maior espera.
Fontes para consultar
Terminou a missão?
Marque apenas quando você conseguir explicar o conceito e concluir o desafio. O progresso fica salvo somente neste navegador.
Próxima: HTTP no Node.js: requisições, rotas e status →