Desafio JavaScript

Execução paralela com Promise.all

Enunciado

Crie três funções assíncronas: buscarUsuario, buscarPosts e buscarComentarios, cada uma recebendo um id e retornando dados após um atraso específico (1000ms, 1500ms e 2000ms, respectivamente). Use Promise.all para buscar todos os dados em paralelo para o id 1 e imprimir o tempo total decorrido. Em seguida, faça o mesmo de forma sequencial (um após o outro) e compare os tempos. Trate possíveis erros com try/catch.

Requisitos

  • As três funções devem ser async e usar await para simular atrasos.
  • Use Promise.all para executar as três buscas em paralelo.
  • Meça e imprima o tempo total de cada abordagem (paralela e sequencial).
  • Trate erros com try/catch em ambos os casos.

Código inicial

// Crie as funções async buscarUsuario, buscarPosts, buscarComentarios
// Cada uma espera um tempo e retorna um objeto/array
// Use Promise.all para buscar em paralelo e meça o tempo
// Depois faça sequencialmente e compare

Saída esperada

Paralelo: usuário, posts, comentários em ~2000ms
Sequencial: usuário, posts, comentários em ~4500ms
Ver dica

Use Date.now() para medir o tempo. Para paralelo, crie as promises e passe para Promise.all. Para sequencial, use await uma após a outra.

Mostrar solução
// Função auxiliar para simular atraso
function esperar(ms) {
  return new Promise((resolve) => setTimeout(resolve, ms));
}

// Busca usuário (1000ms)
async function buscarUsuario(id) {
  await esperar(1000);
  return { id, nome: 'Ana' };
}

// Busca posts (1500ms)
async function buscarPosts(id) {
  await esperar(1500);
  return ['Post 1', 'Post 2'];
}

// Busca comentários (2000ms)
async function buscarComentarios(id) {
  await esperar(2000);
  return ['Comentário 1', 'Comentário 2'];
}

// Execução paralela com Promise.all
async function executarParalelo(id) {
  const inicio = Date.now();
  try {
    const [usuario, posts, comentarios] = await Promise.all([
      buscarUsuario(id),
      buscarPosts(id),
      buscarComentarios(id),
    ]);
    const tempo = Date.now() - inicio;
    console.log(`Paralelo: ${usuario.nome}, ${posts.length} posts, ${comentarios.length} comentários em ~${tempo}ms`);
  } catch (erro) {
    console.error('Erro no paralelo:', erro.message);
  }
}

// Execução sequencial
async function executarSequencial(id) {
  const inicio = Date.now();
  try {
    const usuario = await buscarUsuario(id);
    const posts = await buscarPosts(id);
    const comentarios = await buscarComentarios(id);
    const tempo = Date.now() - inicio;
    console.log(`Sequencial: ${usuario.nome}, ${posts.length} posts, ${comentarios.length} comentários em ~${tempo}ms`);
  } catch (erro) {
    console.error('Erro no sequencial:', erro.message);
  }
}

// Executa ambas as abordagens
async function main() {
  await executarParalelo(1);
  await executarSequencial(1);
}

main();

Passo a passo

  1. Definimos esperar para simular atrasos com setTimeout.
  2. Criamos as três funções async que esperam tempos diferentes e retornam dados fictícios.
  3. Em executarParalelo, medimos o tempo inicial com Date.now().
  4. Criamos um array com as três chamadas de função (sem await ainda) e passamos para Promise.all, que aguarda todas resolverem.
  5. Desestruturamos os resultados e calculamos o tempo total, imprimindo a mensagem formatada.
  6. Em executarSequencial, medimos o tempo e usamos await uma chamada após a outra, somando os atrasos.
  7. Imprimimos o resultado sequencial.
  8. Em main, chamamos ambas as funções na ordem desejada.

Por que funciona

Promise.all recebe um array de promises e retorna uma única Promise que resolve quando todas as promises do array resolverem. Como as operações são independentes, elas podem rodar concorrentemente, reduzindo o tempo total para o maior atraso (2000ms). Já a execução sequencial soma os atrasos (1000+1500+2000 = 4500ms). O try/catch captura erros de qualquer uma das promises rejeitadas.

Erros comuns

  • Usar await antes de passar para Promise.all: se fizer await buscarUsuario(id) e depois Promise.all([...]), a primeira já terá sido aguardada, perdendo o paralelismo.
  • Esquecer de tratar rejeições: Promise.all rejeita imediatamente se qualquer promise falhar; sem try/catch, o erro não será tratado.
  • Medir o tempo incorretamente: usar Date.now() antes e depois de await é correto, mas se colocar dentro do try pode incluir tempo de outras operações.
  • Confundir paralelismo com concorrência: JavaScript é single-thread, mas operações de I/O podem ser concorrentes; Promise.all explora isso.

Outra forma de resolver

Usar Promise.allSettled para aguardar todas as promises, mesmo que algumas falhem, e depois inspecionar os resultados. Útil quando você quer todos os resultados independentemente de erros.

Saída esperada

Paralelo: Ana, 2 posts, 2 comentários em ~2000ms
Sequencial: Ana, 2 posts, 2 comentários em ~4500ms