Guia Completo de Promise.all, Promise.race, Promise.allSettled e Promise.any Já leu

Entendendo Promises Combinadas As Promises são a base da programação assíncrona em JavaScript, mas muitas vezes precisamos trabalhar com múltiplas Promises simultaneamente. Para isso, a linguagem oferece métodos estáticos que combinam várias Promises em uma única operação. Estes métodos são essenciais para otimizar fluxos assíncronos, reduzir tempo de execução e tratar cenários complexos de forma elegante. Cada um deles possui um comportamento único, adequado para diferentes situações do desenvolvimento real. Antes de aprofundar nos métodos, lembre-se: uma Promise pode estar em três estados — pendente, resolvida ou rejeitada. Os métodos de combinação tratam esses estados de formas distintas, e é essa diferença que os torna poderosos quando aplicados corretamente. Promise.all: Tudo ou Nada Comportamento e Características O é o método mais comum. Ele retorna uma Promise que se resolve quando todas as Promises do array forem resolvidas, ou rejeita assim que qualquer uma for rejeitada. Pense nele como uma operação "tudo ou nada": ou você consegue todos os dados, ou

Entendendo Promises Combinadas

As Promises são a base da programação assíncrona em JavaScript, mas muitas vezes precisamos trabalhar com múltiplas Promises simultaneamente. Para isso, a linguagem oferece métodos estáticos que combinam várias Promises em uma única operação. Estes métodos são essenciais para otimizar fluxos assíncronos, reduzir tempo de execução e tratar cenários complexos de forma elegante. Cada um deles possui um comportamento único, adequado para diferentes situações do desenvolvimento real.

Antes de aprofundar nos métodos, lembre-se: uma Promise pode estar em três estados — pendente, resolvida ou rejeitada. Os métodos de combinação tratam esses estados de formas distintas, e é essa diferença que os torna poderosos quando aplicados corretamente.

Promise.all: Tudo ou Nada

Comportamento e Características

O Promise.all() é o método mais comum. Ele retorna uma Promise que se resolve quando todas as Promises do array forem resolvidas, ou rejeita assim que qualquer uma for rejeitada. Pense nele como uma operação "tudo ou nada": ou você consegue todos os dados, ou falha completamente.

Exemplo Prático

const fetchUser = () => new Promise(resolve => 
  setTimeout(() => resolve({ id: 1, name: 'Ana' }), 1000)
);

const fetchPosts = () => new Promise(resolve => 
  setTimeout(() => resolve([{ id: 101, title: 'Post 1' }]), 1500)
);

const fetchComments = () => new Promise((resolve, reject) => 
  setTimeout(() => reject(new Error('Erro ao buscar comentários')), 800)
);

// Caso com sucesso
Promise.all([fetchUser(), fetchPosts()])
  .then(([user, posts]) => {
    console.log('Usuário:', user);
    console.log('Posts:', posts);
  })
  .catch(err => console.error(err));

// Caso com falha (rejeita rapidamente no erro)
Promise.all([fetchUser(), fetchPosts(), fetchComments()])
  .then(results => console.log(results))
  .catch(err => console.error('Erro:', err.message)); // Saída: Erro: Erro ao buscar comentários

Use Promise.all() quando todos os dados são críticos e a operação deve falhar se qualquer um deles não estiver disponível — como validação de múltiplos campos antes de enviar um formulário.

Promise.race: O Primeiro a Chegar

Comportamento e Características

O Promise.race() retorna uma Promise que se resolve ou rejeita assim que a primeira Promise do array for resolvida ou rejeitada. É uma corrida entre as Promises, e apenas o resultado do "vencedor" importa. Os demais resultados são ignorados, embora continuem executando em background.

Exemplo Prático

const fetchFromServer1 = () => new Promise(resolve =>
  setTimeout(() => resolve('Dados do Servidor 1'), 2000)
);

const fetchFromServer2 = () => new Promise(resolve =>
  setTimeout(() => resolve('Dados do Servidor 2'), 800)
);

const timeout = () => new Promise((_, reject) =>
  setTimeout(() => reject(new Error('Timeout')), 1000)
);

Promise.race([fetchFromServer1(), fetchFromServer2()])
  .then(result => console.log(result)) // Saída: Dados do Servidor 2 (mais rápido)
  .catch(err => console.error(err));

// Implementar timeout
Promise.race([fetchFromServer1(), timeout()])
  .then(result => console.log(result))
  .catch(err => console.error('Timeout acionado')); // Saída: Timeout acionado

Use Promise.race() para implementar timeouts, escolher entre múltiplos servidores (usando o mais rápido) ou quando apenas um resultado é necessário. Cuidado: as Promises descartadas continuam consumindo recursos.

Promise.allSettled e Promise.any: Os Métodos Modernos

Promise.allSettled: Aguarde Todos, Independente do Resultado

O Promise.allSettled() aguarda todas as Promises até que sejam liquidadas (resolvidas ou rejeitadas), retornando um array com objetos descrevendo o resultado de cada uma: { status: 'fulfilled', value } ou { status: 'rejected', reason }. Nunca rejeita o resultado final.

const api1 = Promise.resolve('Sucesso 1');
const api2 = Promise.reject(new Error('Erro 2'));
const api3 = Promise.resolve('Sucesso 3');

Promise.allSettled([api1, api2, api3])
  .then(results => {
    console.log(results);
    /* Saída:
    [
      { status: 'fulfilled', value: 'Sucesso 1' },
      { status: 'rejected', reason: Error: Erro 2 },
      { status: 'fulfilled', value: 'Sucesso 3' }
    ]
    */

    const successes = results.filter(r => r.status === 'fulfilled')
      .map(r => r.value);
    console.log('Sucessos:', successes);
  });

Use Promise.allSettled() quando você precisa de todos os resultados, mas alguns podem falhar e você quer tratá-los individualmente — como fazer múltiplas requisições a APIs e reportar sucesso/falha de cada uma.

Promise.any: O Primeiro Sucesso

O Promise.any() retorna uma Promise resolvida assim que qualquer uma das Promises for resolvida com sucesso. Rejeita apenas se todas falharem, retornando um AggregateError contendo todas as razões.

const api1 = Promise.reject(new Error('API 1 falhou'));
const api2 = Promise.reject(new Error('API 2 falhou'));
const api3 = new Promise(resolve => 
  setTimeout(() => resolve('Sucesso na API 3'), 500)
);

Promise.any([api1, api2, api3])
  .then(result => console.log(result)) // Saída: Sucesso na API 3
  .catch(err => console.error(err));

// Todos falham
Promise.any([api1, api2])
  .then(result => console.log(result))
  .catch(err => {
    console.error('Todas falharam:', err.errors);
    // Saída: AggregateError contendo ambos os erros
  });

Use Promise.any() para redundância — múltiplos servidores onde qualquer um que responda com sucesso é suficiente. É perfeito para implementar fallbacks automáticos.

Comparação Prática e Resumo

Método Condição de Sucesso Condição de Rejeição Resultado
all() Todas resolvidas Qualquer rejeição Array de valores
race() Primeira a resolver Primeira a rejeitar Resultado único
allSettled() Sempre (aguarda todas) Nunca Array com status de cada uma
any() Qualquer sucesso Todas rejeitadas Primeiro valor bem-sucedido

Conclusão

Dominar esses quatro métodos é fundamental para trabalhar eficientemente com operações assíncronas em JavaScript. Promise.all() garante completude total, Promise.race() otimiza velocidade, Promise.allSettled() oferece granularidade na análise de resultados, e Promise.any() implementa resiliência através de redundância. Na prática, você usará all() em 70% dos casos, mas conhecer os outros diferencia um desenvolvedor senior de um júnior.

Referências


Artigos relacionados