<h2>Entendendo Promises Combinadas</h2>
<p>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.</p>
<p>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.</p>
<h2>Promise.all: Tudo ou Nada</h2>
<h3>Comportamento e Características</h3>
<p>O <code>Promise.all()</code> é o método mais comum. Ele retorna uma Promise que se resolve quando <strong>todas</strong> as Promises do array forem resolvidas, ou rejeita assim que <strong>qualquer uma</strong> for rejeitada. Pense nele como uma operação "tudo ou nada": ou você consegue todos os dados, ou falha completamente.</p>
<h3>Exemplo Prático</h3>
<pre><code class="language-javascript">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</code></pre>
<p>Use <code>Promise.all()</code> 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.</p>
<h2>Promise.race: O Primeiro a Chegar</h2>
<h3>Comportamento e Características</h3>
<p>O <code>Promise.race()</code> retorna uma Promise que se resolve ou rejeita assim que <strong>a primeira</strong> 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.</p>
<h3>Exemplo Prático</h3>
<pre><code class="language-javascript">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</code></pre>
<p>Use <code>Promise.race()</code> 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.</p>
<h2>Promise.allSettled e Promise.any: Os Métodos Modernos</h2>
<h3>Promise.allSettled: Aguarde Todos, Independente do Resultado</h3>
<p>O <code>Promise.allSettled()</code> aguarda <strong>todas</strong> as Promises até que sejam liquidadas (resolvidas ou rejeitadas), retornando um array com objetos descrevendo o resultado de cada uma: <code>{ status: 'fulfilled', value }</code> ou <code>{ status: 'rejected', reason }</code>. Nunca rejeita o resultado final.</p>
<pre><code class="language-javascript">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);
});</code></pre>
<p>Use <code>Promise.allSettled()</code> 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.</p>
<h3>Promise.any: O Primeiro Sucesso</h3>
<p>O <code>Promise.any()</code> retorna uma Promise resolvida assim que <strong>qualquer uma</strong> das Promises for resolvida com sucesso. Rejeita apenas se <strong>todas</strong> falharem, retornando um <code>AggregateError</code> contendo todas as razões.</p>
<pre><code class="language-javascript">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
});</code></pre>
<p>Use <code>Promise.any()</code> para redundância — múltiplos servidores onde qualquer um que responda com sucesso é suficiente. É perfeito para implementar fallbacks automáticos.</p>
<h2>Comparação Prática e Resumo</h2>
<div class="table-wrap"><table><thead><tr><th>Método</th><th>Condição de Sucesso</th><th>Condição de Rejeição</th><th>Resultado</th></tr></thead><tbody><tr><td><code>all()</code></td><td>Todas resolvidas</td><td>Qualquer rejeição</td><td>Array de valores</td></tr><tr><td><code>race()</code></td><td>Primeira a resolver</td><td>Primeira a rejeitar</td><td>Resultado único</td></tr><tr><td><code>allSettled()</code></td><td>Sempre (aguarda todas)</td><td>Nunca</td><td>Array com status de cada uma</td></tr><tr><td><code>any()</code></td><td>Qualquer sucesso</td><td>Todas rejeitadas</td><td>Primeiro valor bem-sucedido</td></tr></tbody></table></div>
<h2>Conclusão</h2>
<p>Dominar esses quatro métodos é fundamental para trabalhar eficientemente com operações assíncronas em JavaScript. <code>Promise.all()</code> garante completude total, <code>Promise.race()</code> otimiza velocidade, <code>Promise.allSettled()</code> oferece granularidade na análise de resultados, e <code>Promise.any()</code> implementa resiliência através de redundância. Na prática, você usará <code>all()</code> em 70% dos casos, mas conhecer os outros diferencia um desenvolvedor senior de um júnior.</p>
<h2>Referências</h2>
<ul>
<li><a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/all" target="_blank" rel="noopener noreferrer">MDN - Promise.all()</a></li>
<li><a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/race" target="_blank" rel="noopener noreferrer">MDN - Promise.race()</a></li>
<li><a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/allSettled" target="_blank" rel="noopener noreferrer">MDN - Promise.allSettled()</a></li>
<li><a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/any" target="_blank" rel="noopener noreferrer">MDN - Promise.any()</a></li>
<li><a href="https://javascript.info/promise-basics#promise-api" target="_blank" rel="noopener noreferrer">JavaScript.info - Promise combinators</a></li>
</ul>