Promises e Async/Await em JavaScript
As Promises são uma das funcionalidades mais importantes do JavaScript moderno, permitindo o tratamento elegante de operações assíncronas.
O que são Promises?
Uma Promise é um objeto que representa a eventual conclusão (ou falha) de uma operação assíncrona e seu valor resultante.
const minhaPromise = new Promise((resolve, reject) => {
// Operação assíncrona
setTimeout(() => {
const sucesso = true;
if (sucesso) {
resolve("Operação concluída com sucesso!");
} else {
reject("Algo deu errado!");
}
}, 1000);
});
minhaPromise
.then(resultado => console.log(resultado))
.catch(erro => console.error(erro));
Estados de uma Promise
Uma Promise pode estar em um de três estados:
- Pending: Estado inicial, nem fulfilled nem rejected
- Fulfilled: A operação foi concluída com sucesso
- Rejected: A operação falhou
Async/Await - Sintaxe Moderna
O async/await é uma sintaxe mais limpa para trabalhar com Promises, tornando o código assíncrono mais legível.
async function buscarDados() {
try {
const resposta = await fetch('/api/dados');
const dados = await resposta.json();
console.log('Dados recebidos:', dados);
return dados;
} catch (erro) {
console.error('Erro ao buscar dados:', erro);
throw erro;
}
}
// Uso da função
buscarDados()
.then(dados => {
// Processar dados
})
.catch(erro => {
// Tratar erro
});
Padrões Avançados
Promise.all() - Execução Paralela
Use Promise.all() quando precisar executar múltiplas operações assíncronas em paralelo e aguardar todas elas.
async function buscarTodosDados() {
try {
const [usuarios, posts, comentarios] = await Promise.all([
fetch('/api/usuarios').then(r => r.json()),
fetch('/api/posts').then(r => r.json()),
fetch('/api/comentarios').then(r => r.json())
]);
return { usuarios, posts, comentarios };
} catch (erro) {
// Se qualquer uma falhar, todas falham
console.error('Erro ao buscar dados:', erro);
}
}
Promise.allSettled() - Aguardar Todas
Diferente do Promise.all(), o allSettled() aguarda todas as promises terminarem, independente de sucesso ou falha.
async function buscarDadosComFallback() {
const resultados = await Promise.allSettled([
fetch('/api/dados-primarios'),
fetch('/api/dados-secundarios'),
fetch('/api/dados-cache')
]);
const sucessos = resultados
.filter(resultado => resultado.status === 'fulfilled')
.map(resultado => resultado.value);
const falhas = resultados
.filter(resultado => resultado.status === 'rejected')
.map(resultado => resultado.reason);
console.log('Sucessos:', sucessos.length);
console.log('Falhas:', falhas.length);
}
Boas Práticas
- Sempre trate erros com try/catch ou .catch()
- Use async/await para código mais legível
- Evite callback hell usando Promises
- Use Promise.all() para operações paralelas
- Considere timeouts para operações que podem travar
function comTimeout(promise, ms) {
return Promise.race([
promise,
new Promise((_, reject) =>
setTimeout(() => reject(new Error('Timeout')), ms)
)
]);
}
// Uso
try {
const dados = await comTimeout(
fetch('/api/dados-lentos'),
5000 // 5 segundos de timeout
);
} catch (erro) {
if (erro.message === 'Timeout') {
console.log('Operação muito lenta, cancelada');
}
}
Conclusão
Promises e async/await são fundamentais para o JavaScript moderno. Dominar esses conceitos é essencial para criar aplicações robustas e performáticas.