Desafio JavaScript

Promise.all vs Promise.allSettled

Enunciado

Crie uma função buscarUsuario(id) que retorna uma Promise que resolve após 500ms com um objeto { id, nome: 'Usuário ' + id } se id > 0, ou rejeita com new Error('ID inválido') se id <= 0. Use Promise.all() para buscar os IDs [1, 2, 3] e exiba os resultados. Depois, use Promise.allSettled() para buscar os IDs [4, -1, 5] e exiba o status e o valor/erro de cada um.

Requisitos

  • A função buscarUsuario deve retornar uma Promise que resolve ou rejeita conforme a condição.
  • Use Promise.all() com os IDs [1, 2, 3] e exiba os resultados no console.
  • Use Promise.allSettled() com os IDs [4, -1, 5] e exiba o status e o valor/erro de cada resultado.
  • Trate erros do Promise.all() com .catch().

Código inicial

function buscarUsuario(id) {
  // Seu código aqui
}

// Promise.all
Promise.all([1, 2, 3].map(buscarUsuario))
  .then(resultados => {
    // exiba os resultados
  })
  .catch(erro => {
    // exiba o erro
  });

// Promise.allSettled
Promise.allSettled([4, -1, 5].map(buscarUsuario))
  .then(resultados => {
    // exiba o status e valor/erro de cada resultado
  });

Saída esperada

Promise.all resultados: [ { id: 1, nome: 'Usuário 1' }, { id: 2, nome: 'Usuário 2' }, { id: 3, nome: 'Usuário 3' } ]
Promise.allSettled:
Status: fulfilled, Valor: { id: 4, nome: 'Usuário 4' }
Status: rejected, Erro: ID inválido
Status: fulfilled, Valor: { id: 5, nome: 'Usuário 5' }
Ver dica

Para Promise.allSettled, cada resultado tem uma propriedade status que pode ser 'fulfilled' ou 'rejected'. Se for 'fulfilled', o valor está em result.value; se for 'rejected', o erro está em result.reason.

Mostrar solução
function buscarUsuario(id) {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      if (id > 0) {
        resolve({ id, nome: `Usuário ${id}` });
      } else {
        reject(new Error('ID inválido'));
      }
    }, 500);
  });
}

// Promise.all: resolve todas ou rejeita na primeira falha
Promise.all([1, 2, 3].map(buscarUsuario))
  .then(resultados => {
    console.log('Promise.all resultados:', resultados);
  })
  .catch(erro => {
    console.error('Promise.all erro:', erro.message);
  });

// Promise.allSettled: sempre resolve com o status de cada promise
Promise.allSettled([4, -1, 5].map(buscarUsuario))
  .then(resultados => {
    console.log('Promise.allSettled:');
    resultados.forEach(resultado => {
      if (resultado.status === 'fulfilled') {
        console.log(`Status: ${resultado.status}, Valor:`, resultado.value);
      } else {
        console.log(`Status: ${resultado.status}, Erro: ${resultado.reason.message}`);
      }
    });
  });

Passo a passo

  1. A função buscarUsuario retorna uma Promise que, após 500ms, resolve com um objeto se id > 0 ou rejeita com um erro se id <= 0.
  2. Usamos [1, 2, 3].map(buscarUsuario) para criar um array de Promises, uma para cada ID.
  3. Promise.all() recebe esse array e retorna uma nova Promise que resolve com um array de resultados quando todas forem resolvidas.
  4. Encadeamos .then() para exibir os resultados e .catch() para tratar qualquer rejeição.
  5. Para Promise.allSettled(), usamos [4, -1, 5].map(buscarUsuario) e passamos para o método.
  6. Promise.allSettled() sempre resolve com um array de objetos de resultado, independentemente de sucesso ou falha.
  7. No .then(), iteramos sobre os resultados e verificamos resultado.status para exibir o valor ou o erro.

Por que funciona

Promise.all() é útil quando você precisa que todas as Promises sejam bem-sucedidas para prosseguir; se qualquer uma falhar, a Promise resultante é rejeitada imediatamente. Já Promise.allSettled() é mais tolerante: ela espera que todas terminem e fornece um relatório completo, permitindo lidar com sucessos e falhas individualmente. Isso é crucial em cenários onde algumas operações podem falhar sem comprometer as demais.

Erros comuns

  • Usar Promise.all() quando algumas Promises podem falhar: isso fará com que todo o conjunto seja rejeitado, perdendo os resultados das que tiveram sucesso. Use Promise.allSettled() nesses casos.
  • Esquecer de tratar a rejeição do Promise.all(): sem .catch(), um erro não tratado pode encerrar o processo.
  • Acessar result.value sem verificar o status: em Promise.allSettled(), se o status for 'rejected', value é undefined e o erro está em reason.
  • Não mapear corretamente os IDs para Promises: passar um array de números diretamente para Promise.all() causa erro, pois não são Promises. Use .map().

Outra forma de resolver

Usar async/await com Promise.allSettled():

async function main() {
  try {
    const resultados = await Promise.all([1, 2, 3].map(buscarUsuario));
    console.log('Promise.all resultados:', resultados);
  } catch (erro) {
    console.error('Promise.all erro:', erro.message);
  }

  const settled = await Promise.allSettled([4, -1, 5].map(buscarUsuario));
  console.log('Promise.allSettled:');
  settled.forEach(r => {
    if (r.status === 'fulfilled') {
      console.log(`Status: ${r.status}, Valor:`, r.value);
    } else {
      console.log(`Status: ${r.status}, Erro: ${r.reason.message}`);
    }
  });
}
main();

Essa forma é mais limpa, mas o enunciado pede o uso explícito de .then() e .catch().

Saída esperada

Promise.all resultados: [ { id: 1, nome: 'Usuário 1' }, { id: 2, nome: 'Usuário 2' }, { id: 3, nome: 'Usuário 3' } ]
Promise.allSettled:
Status: fulfilled, Valor: { id: 4, nome: 'Usuário 4' }
Status: rejected, Erro: ID inválido
Status: fulfilled, Valor: { id: 5, nome: 'Usuário 5' }