Trabalhar com múltiplas promises simultaneamente é algo comum no JavaScript, mas você sabe quando usar Promise.all, Promise.race ou Promise.allSettled? Cada um desses métodos tem um propósito específico e escolher o certo pode fazer toda a diferença na qualidade do seu código.
Neste artigo, vou mostrar as diferenças práticas entre eles e quando usar cada um. Vamos lá!
Promise.all - Esperando todas as promises
O Promise.all é o método mais conhecido e usado. Ele recebe um array de promises e retorna uma nova promise que só é resolvida quando todas as promises do array forem resolvidas.
const buscarUsuario = () => new Promise((resolve) => {
setTimeout(() => resolve({ nome: 'João' }), 100)
})
const buscarPosts = () => new Promise((resolve) => {
setTimeout(() => resolve(['Post 1', 'Post 2']), 200)
})
const buscarComentarios = () => new Promise((resolve) => {
setTimeout(() => resolve(['Comentário 1', 'Comentário 2']), 150)
})
Promise.all([buscarUsuario(), buscarPosts(), buscarComentarios()])
.then(([usuario, posts, comentarios]) => {
console.log('Usuário:', usuario)
console.log('Posts:', posts)
console.log('Comentários:', comentarios)
})
Quando usar Promise.all
- Quando você precisa de todos os resultados para continuar
- Para fazer múltiplas requisições em paralelo e economizar tempo
- Quando uma falha deve interromper todo o processo
Cuidado: Se qualquer promise rejeitar, o Promise.all rejeita imediatamente e você não recebe os resultados das outras promises, mesmo que elas tenham sido bem-sucedidas.
const promise1 = Promise.resolve('Sucesso')
const promise2 = Promise.reject('Erro!')
const promise3 = Promise.resolve('Outro sucesso')
Promise.all([promise1, promise2, promise3])
.then(resultados => console.log(resultados))
.catch(erro => console.log('Falhou:', erro)) // Vai cair aqui
Promise.race - A primeira a terminar vence
O Promise.race retorna a primeira promise que for resolvida ou rejeitada. Literalmente uma corrida entre promises!
const requisicaoRapida = () => new Promise((resolve) => {
setTimeout(() => resolve('Resposta rápida'), 100)
})
const requisicaoLenta = () => new Promise((resolve) => {
setTimeout(() => resolve('Resposta lenta'), 500)
})
Promise.race([requisicaoRapida(), requisicaoLenta()])
.then(resultado => console.log(resultado)) // 'Resposta rápida'
Quando usar Promise.race
- Timeout de requisições: Cancelar operações que demoram muito
- Múltiplas fontes: Buscar dados de várias APIs e usar a primeira que responder
- Fallback rápido: Tentar várias estratégias e usar a primeira que funcionar
Exemplo prático - Timeout:
const buscarDados = () => new Promise((resolve) => {
setTimeout(() => resolve('Dados da API'), 3000)
})
const timeout = (ms) => new Promise((_, reject) => {
setTimeout(() => reject('Timeout!'), ms)
})
Promise.race([buscarDados(), timeout(2000)])
.then(dados => console.log(dados))
.catch(erro => console.log('Erro:', erro)) // Vai dar timeout
Já falamos mais sobre o Promise.race aqui no blog, confira!
Promise.allSettled - Resultados de todas, independente do status
O Promise.allSettled é o mais recente dos três. Ele sempre espera todas as promises terminarem, não importa se foram resolvidas ou rejeitadas, e retorna um array com os resultados de cada uma.
const promise1 = Promise.resolve('Sucesso')
const promise2 = Promise.reject('Erro!')
const promise3 = Promise.resolve('Outro sucesso')
Promise.allSettled([promise1, promise2, promise3])
.then(resultados => {
console.log(resultados)
/*
[
{ status: 'fulfilled', value: 'Sucesso' },
{ status: 'rejected', reason: 'Erro!' },
{ status: 'fulfilled', value: 'Outro sucesso' }
]
*/
})
Quando usar Promise.allSettled
- Quando você quer saber o resultado de todas as operações, mesmo as que falharam
- Para fazer análise de sucesso/falha em lote
- Quando falhas parciais são aceitáveis
Exemplo prático - Upload de múltiplos arquivos:
const uploadArquivo = (arquivo, devefalhar = false) => {
return new Promise((resolve, reject) => {
setTimeout(() => {
if (devefalhar) {
reject(`Falha ao enviar ${arquivo}`)
} else {
resolve(`${arquivo} enviado com sucesso`)
}
}, 100)
})
}
const arquivos = ['foto1.jpg', 'foto2.jpg', 'foto3.jpg']
const uploads = [
uploadArquivo(arquivos[0]),
uploadArquivo(arquivos[1], true), // Vai falhar
uploadArquivo(arquivos[2])
]
Promise.allSettled(uploads)
.then(resultados => {
resultados.forEach((resultado, i) => {
if (resultado.status === 'fulfilled') {
console.log(`✓ ${arquivos[i]}: ${resultado.value}`)
} else {
console.log(`✗ ${arquivos[i]}: ${resultado.reason}`)
}
})
})
Tabela de decisão rápida
| Método | O que faz | Use quando | Falha |
|---|---|---|---|
| Promise.all | Espera todas terminarem | Precisa de todos os resultados | Rejeita ao primeiro erro |
| Promise.race | Retorna a primeira a terminar | Quer o resultado mais rápido ou timeout | Rejeita se a primeira rejeitar |
| Promise.allSettled | Espera todas e retorna status de cada | Quer saber todos os resultados (sucesso e falha) | Nunca rejeita |
Combinando com async/await
Todos esses métodos funcionam perfeitamente com async/await, deixando o código ainda mais limpo:
async function buscarTodosDados() {
try {
const [usuario, posts, comentarios] = await Promise.all([
buscarUsuario(),
buscarPosts(),
buscarComentarios()
])
console.log({ usuario, posts, comentarios })
} catch (erro) {
console.log('Erro ao buscar dados:', erro)
}
}
buscarTodosDados()
Conclusão
Escolher o método certo para trabalhar com múltiplas promises pode melhorar muito a performance e a confiabilidade da sua aplicação:
- Use Promise.all quando precisar de todos os resultados e uma falha deve interromper tudo
- Use Promise.race para implementar timeouts ou buscar dados de múltiplas fontes
- Use Promise.allSettled quando precisar processar todos os resultados, independente de sucesso ou falha
Entender essas diferenças vai fazer você escrever código assíncrono muito mais eficiente e robusto!
Curta o DevPleno no Facebook, inscreva-se no canal e não se esqueça de cadastrar seu e-mail para não perder as novidades. Deixe suas dúvidas e sugestões nos comentários. Abraço!
Mestre em Sistemas de Informação pela USP e criador do DevPleno. Iniciou sua carreira como professor com apenas 18 anos em um curso técnico, foram 11 anos em sala de aula formando desenvolvedores fullstack no sul de Minas Gerais.