O erro que "voa" em outro momento
Tratar erros em código assíncrono é diferente porque a falha não ocorre na linha onde você escreveu a chamada, mas mais tarde, quando a promessa é resolvida. Há duas ferramentas principais.
1. try/catch com await
Dentro de uma função async, await transforma uma rejeição em uma
exceção que você pode capturar com um try...catch normal, como se fosse código
síncrono:
async function carregar() {
try {
const dados = await pedirDados(); // se for rejeitada, pula para o catch
return dados;
} catch (erro) {
console.log("Falhou:", erro.message);
return null; // valor padrão
}
}
2. .catch() encadeado
Sem async/await, usa-se .catch() no final da cadeia:
pedirDados()
.then((dados) => usar(dados))
.catch((erro) => console.log("Falhou:", erro.message));
O erro clássico: try/catch SEM await
Isto NÃO funciona como você espera:
async function ruim() {
try {
pedirDados(); // faltou o await!
} catch (erro) {
console.log("Isto nunca é executado");
}
}
Sem await, a linha pedirDados() apenas cria a promessa e segue
adiante; o try já terminou quando, muito depois, a promessa é rejeitada. O
catch síncrono não consegue capturar uma falha que ocorre fora do seu tempo de
vida. É como fechar a rede de segurança antes de o trapezista saltar.
Regra: um
try/catchsó captura a rejeição de uma promessa se você colocarawaitna frente (ou se devolver a promessa e tratar o erro com.catch).
Rejeições não capturadas
Se uma promessa é rejeitada e ninguém a trata (nem await em um try, nem um
.catch), ocorre um unhandled rejection. No navegador você verá um
warning no console; no Node, por padrão, encerra o processo. Por isso toda
promessa que possa falhar deveria ter o seu tratador de erro.
// ❌ Rejeição sem tratamento: warning / processo derrubado
Promise.reject(new Error("ninguém me captura"));
// ✅ Tratada
Promise.reject(new Error("agora me capturam")).catch((e) => console.log(e.message));
Exemplos
try/catch com await devolve um valor padrão
function falhar() {
return Promise.reject(new Error("boom"));
}
async function seguro() {
try {
return await falhar();
} catch (e) {
return "valor padrão";
}
}
seguro().then((v) => console.log(v)); // "valor padrão"
Sem await, o catch NÃO captura a rejeição
function falhar() {
return Promise.reject(new Error("boom"));
}
async function ruim() {
try {
const p = falhar(); // sem await
p.catch(() => {}); // silenciamos para não quebrar a demo
return "o try terminou sem capturar nada";
} catch (e) {
return "isto NÃO é executado";
}
}
ruim().then((v) => console.log(v));