O que é uma Promise?
Uma Promise é um objeto JavaScript que representa o resultado eventual (sucesso ou falha) de uma operação assíncrona. Ela funciona como um "contrato": você envia uma tarefa e receberá uma resposta no futuro. Uma Promise pode estar em três estados: pending (aguardando), fulfilled (resolvida com sucesso) ou rejected (rejeitada com erro).
const minhaPromise = new Promise((resolve, reject) => {
setTimeout(() => {
resolve('Operação concluída com sucesso!');
}, 1000);
});
console.log(minhaPromise); // Promise { <pending> }
As Promises eliminam o "callback hell" e tornam o código assíncrono mais legível e previsível. Quando você cria uma Promise, passa uma função executora com dois parâmetros: resolve (para sucesso) e reject (para erro). A Promise resolve ou rejeita apenas uma vez, permanecendo naquele estado para sempre.
Then, Catch e Finally: Tratando Resultados
O método .then()
O .then() recebe até dois argumentos: callbacks para sucesso e erro (este último opcional). Retorna uma nova Promise, permitindo encadeamento. Isso é fundamental: cada .then() cria uma nova Promise com o retorno anterior.
const buscarDados = new Promise((resolve, reject) => {
setTimeout(() => {
resolve({ id: 1, nome: 'João' });
}, 1000);
});
buscarDados
.then(dados => {
console.log('Dados recebidos:', dados);
return dados.id; // Retorna nova Promise resolvida com o id
})
.then(id => {
console.log('ID processado:', id); // 1
});
O método .catch()
O .catch() captura erros em qualquer ponto da cadeia. Ele recebe uma função que trata a rejeição. Usar .catch() é a abordagem moderna (preferível ao segundo argumento de .then()).
const requisicaoFalha = new Promise((resolve, reject) => {
setTimeout(() => {
reject(new Error('Falha na conexão'));
}, 1000);
});
requisicaoFalha
.then(resultado => console.log(resultado))
.catch(erro => {
console.error('Erro capturado:', erro.message); // Falha na conexão
});
O método .finally()
O .finally() executa sempre, independente de sucesso ou erro. Use-o para limpeza de recursos (fechar conexões, parar spinners de carregamento).
let carregando = true;
fetch('https://api.exemplo.com/dados')
.then(response => response.json())
.then(dados => console.log(dados))
.catch(erro => console.error(erro))
.finally(() => {
carregando = false;
console.log('Requisição finalizada');
});
Encadeamento de Promises: Composição Poderosa
Encadeamento significa conectar múltiplas operações assíncronas em sequência. Cada .then() espera o anterior terminar antes de executar. Retornar uma Promise ou um valor comum do .then() permite o próximo na cadeia processar o resultado.
function buscarUsuario(id) {
return new Promise((resolve) => {
setTimeout(() => {
resolve({ id: id, nome: 'Ana', empresaId: 5 });
}, 500);
});
}
function buscarEmpresa(empresaId) {
return new Promise((resolve) => {
setTimeout(() => {
resolve({ id: empresaId, nome: 'Tech Corp' });
}, 500);
});
}
// Encadeamento
buscarUsuario(1)
.then(usuario => {
console.log('Usuário:', usuario.nome);
return buscarEmpresa(usuario.empresaId); // Retorna nova Promise
})
.then(empresa => {
console.log('Empresa:', empresa.nome);
})
.catch(erro => console.error('Algo deu errado:', erro))
.finally(() => console.log('Processo completo'));
Neste exemplo, buscarEmpresa() só executa após buscarUsuario() resolver e retornar o usuário. O encadeamento mantém a ordem e o contexto claros. Dica importante: sempre retorne uma Promise ou um valor do .then() se quiser que o próximo acesse esse resultado.
Padrões Avançados e Boas Práticas
Ao trabalhar com múltiplas Promises em paralelo (não sequencial), use Promise.all() ou Promise.race(). O Promise.all() espera todas resolverem; o Promise.race() retorna a primeira a resolver ou rejeitar.
const promise1 = new Promise(resolve => setTimeout(() => resolve('A'), 500));
const promise2 = new Promise(resolve => setTimeout(() => resolve('B'), 1000));
Promise.all([promise1, promise2])
.then(resultados => {
console.log(resultados); // ['A', 'B']
});
Promise.race([promise1, promise2])
.then(primeiro => {
console.log(primeiro); // 'A' (a mais rápida)
});
Evite erros comuns: não coloque .catch() no meio da cadeia sem retornar uma Promise (quebra o fluxo), não esqueça de retornar valores/Promises em .then() se o próximo depender deles, e sempre use .catch() no final ou trate erros adequadamente para evitar rejeições não tratadas.
Conclusão
Dominar Promises é essencial para JavaScript moderno. Os três pilares são: .then() para processar sucessos e encadear operações, .catch() para tratar erros de forma centralizada, e .finally() para limpeza garantida. O encadeamento transforma código assíncrono complexo em fluxos legíveis e previsíveis. Pratique combinando essas técnicas em projetos reais — requisições HTTP, manipulação de arquivos, timers — para consolidar o aprendizado.