As Promises surgiram em 2015, com o lançamento da especificação ECMAScript 6 (ES2015) do JavaScript, para deixar nossa experiência como desenvolvedor menos complicada ao lidar com operações assíncronas.
Se você estuda ou trabalha com JavaScript, com certeza já usou um Promise.all()
ou um Promise.race()
por aí. E pra facilitar ainda mais a vida do desenvolvedor, com o lançamento de versões mais atuais do JavaScript, tivemos acesso a dois novos métodos de Promises: Promise.allSettled()
e Promise.any()
(ES11 e ES2021, respectivamente).
Mas qual a diferença entre eles e quando devemos usar cada um?
Sumário
Promise.all vs Promise.allSettled: foco no resultado
Promise.race vs Promise.any: foco na velocidade
Promise.all vs Promise.allSettled: foco no resultado
Imagine que você está desenvolvendo uma aplicação que, em determinado momento, precisa executar diferentes chamadas à API. Se essas chamadas forem independentes entre si, uma boa opção seria executar todas as chamadas simultaneamente, melhorando a performance da aplicação, além de deixar o código mais conciso.
Promise.all()
- Recebe um array de Promises como argumento;
- Executa as operações simultaneamente (em paralelo);
- Resolve quando todas as Promises são resolvidas com sucesso;
- Rejeita imediatamente se uma das Promises falhar, bloqueando a execução das Promises seguintes.
async function buscarDadosParalelo() {
const [usuarios, produtos] = await Promise.all([
fetch('/api/usuarios').then(resp => resp.json()),
fetch('/api/produtos').then(resp => resp.json()),
]);
return { usuarios, produtos };
}
O Promise.all() é bastante útil quando você precisa garantir que todas as Promises tenham sucesso e a função receba todos os resultados que precisa antes de executar alguma outra ação.
Promise.allSettled()
- Também recebe um array de Promises como argumento;
- Também executa as operações simultaneamente (em paralelo);
- Resolve quando todas as Promises finalizam sua execução, seja com sucesso ou falha, retornando um objeto para cada Promise contendo o status desta (
fulfilled
ourejected
); - Nunca rejeita e, consequentemente, não bloqueia a execução das Promises.
async function buscarDadosParaleloComFalhas() {
const resultados = await Promise.allSettled([
fetch('/api/usuarios').then(resp => resp.json()),
fetch('/api/produtos').then(resp => resp.json()),
]);
// Verificar cada resultado individualmente:
const dados = resultados.map(resultado => {
if (resultado.status === 'fulfilled') {
return resultado.value;
} else {
console.error(resultado.reason);
return null;
}
});
return dados;
}
O Promise.allSettled() não bloqueia a aplicação caso alguma Promise finalize com falha, além de permitir tratamento individual do sucesso ou erro de cada chamada. Ele é como um relatório de status, que aguarda todas as requisições resolverem ou rejeitarem e permite ao usuário avaliar e tratar cada caso.
Promise.race vs Promise.any: foco na velocidade
Por outro lado, quando falamos de Promise.race()
e Promise.any()
, estamos falando de abordagens para lidar com a primeira resposta em um conjunto de operações assíncronas.
Promise.race()
- Recebe um array de Promises com argumento;
- Executa as operações simultaneamente (em paralelo);
- Retorna a primeira Promise que for concluída OU rejeitada.
async function buscarDadosUsuario() {
const timeout = new Promise((_, reject) => {
setTimeout(() => reject('Timeout!'), 5000);
});
try {
// Usa race para pegar o primeiro resultado disponível
const resultado = await Promise.race([
buscarCache,
buscarBancoLocal,
buscarAPI,
timeout
]);
return resultado;
} catch (erro) {
console.log(erro);
// A execução para aqui se houver erro
}
}
O Promise.race() é bastante útil quando precisamos de uma resposta rápida — o primeiro retorno disponível, independente de ser sucesso ou erro. Também é bastante utilizado com timeouts, como no exemplo acima, para garantir que tenhamos qualquer resposta dentro de um limite de tempo e possamos evitar que requisições lentas continuem consumindo recursos.
Promise.any()
- Também recebe um array de Promises com argumento;
- Executa as operações simultaneamente (em paralelo);
- Retorna a primeira Promise que for concluída com sucesso, ignorando as rejeições;
- Só rejeita se todas as Promises forem rejeitadas.
async function buscarDadosUsuario() {
try {
// Retorna a primeira busca que responder com sucesso
const resultado = await Promise.any([
buscarCache,
buscarBancoLocal,
buscarAPI
]);
return resultado;
} catch (erro) {
console.log(erro);
// Só cai aqui se TODAS as buscas falharem
}
}
O Promise.any() é útil quando você precisa que pelo menos uma das requisições seja concluída com sucesso, sendo ideal para fallbacks e redundâncias, como carregar um recurso de múltiplas fontes (CDN, local, etc.) ou conectar-se a diferentes servidores em caso de falha.
Em um mundo digital cada vez mais assíncrono, entender como gerenciar múltiplas operações simultâneas em JavaScript tornou-se uma habilidade essencial para desenvolvedores. Nesse artigo, exploramos com alguns exemplos alguns métodos importantes das Promises, mostrando como cada um deles funciona e, mais importante, quando e por que você deveria escolher um em detrimento do outro.
Até a próxima (e prometo que volto em breve)!
Top comments (0)