Como usar try
e catch
com JavaScript — guia prático
O que é try...catch
e quando usar
O try...catch
é uma estrutura do JavaScript usada para capturar exceções em tempo de execução — ou seja, pegar erros quando eles ocorrem e reagir de maneira controlada, evitando que a aplicação quebre abruptamente. A construção típica envolve um bloco try
(onde você coloca código que pode lançar), um catch
(para tratar o erro) e opcionalmente um finally
(que roda sempre, mesmo quando há retorno ou exceção).
Sintaxe básica e exemplos
Estrutura mínima:
try {
// código que pode lançar
} catch (err) {
// tratamento do erro
} finally {
// executa sempre (opcional)
}
Exemplo simples:
try {
const parsed = JSON.parse(userInput);
console.log(parsed);
} catch (err) {
console.error("Erro ao parsear JSON:", err.message);
} finally {
console.log("Tentativa de parse concluída.");
}
O catch
recebe o objeto de erro (por convenção chamado err
ou error
), que tem propriedades como message
e stack
. Use essas propriedades com parcimônia — a mensagem deve ser clara e útil para depuração.
Optional catch binding (ES2019)
Se você precisa apenas executar lógica quando ocorre um erro, mas não usa o objeto de erro dentro do catch
, a partir do ES2019 é permitido omitir a variável de captura:
try {
doSomething();
} catch {
// não precisamos do objeto 'err' — apenas tratamos
cleanup();
}
Esse recurso facilita códigos mais enxutos quando a informação do erro não é necessária para o tratamento. Ferramentas de transpilação (como Babel) e navegadores modernos suportam essa sintaxe.
try
com async/await
e Promises
Em operações assíncronas, o padrão mais legível hoje é usar async/await
. Quando você usa await
, coloque-o dentro de um try
para capturar rejeições da Promise — caso contrário, uma rejeição não tratada pode interromper o fluxo.
async function fetchUser(id) {
try {
const res = await fetch(`/users/${id}`);
if (!res.ok) throw new Error('Falha na requisição: ' + res.status);
return await res.json();
} catch (err) {
console.error('Erro ao buscar usuário:', err);
// decidir: tratar, re-lançar ou devolver um valor padrão
throw err; // rethrow se não puder tratar aqui
}
}
Para situações em que você quer capturar apenas a Promise específica e continuar sem interromper o restante, prefira isolar o await
em seu próprio try
ou use promise.then(...).catch(...)
. Evite blocos try
gigantes que englobem muita lógica — isso dificulta entender a origem do erro.
Error.cause
e encadeamento de erros (ES2022)
Quando você pega um erro e cria outro (por exemplo, para adicionar contexto), é útil manter a causa original. O padrão moderno é usar a propriedade cause
do Error
, introduzida no ES2022, que permite encadear erros e preservar informações de diagnóstico.
try {
await doLowLevel();
} catch (err) {
throw new Error('Falha ao processar pedido', { cause: err });
}
Ferramentas de logging e observabilidade conseguem ler esse cause
para mostrar uma cadeia de falhas — isso melhora muito o diagnóstico em produção.
Boas práticas — o que fazer e o que evitar
Tratar erros corretamente é tanto sobre código quanto sobre decisões de produto. Seguem recomendações práticas:
- Capture apenas o que você pode tratar: não engula erros silenciando-os sem ação. Se você não tem como resolver no local, registre e re-lance.
- Use mensagens claras: mensagens de erro devem facilitar a correção (ex.: "Conexão com banco falhou: timeout 5s").
- Prefira erros customizados quando fizer sentido: crie classes que estendam
Error
para diferenciar tipos (ex.:ValidationError
,NotFoundError
). - Não abuse de
try
global: blocos muito grandes tornam difícil achar a origem da falha. - Log e monitore: registre stack traces em logs centralizados e configure alertas para erros críticos.
- Falhas visíveis para o usuário: trate erros esperados (ex.: validação) com mensagens amigáveis; internamente, guarde a stack para devs.
Exemplos práticos e padrões recomendados
1) Isolar operações arriscadas
try {
const users = await getUsers(); // operação segura
// ... processos que dependem de users
} catch (err) {
// tratar especificamente a falha de getUsers
reportError(err);
// alternativa: fallback para lista vazia
return [];
}
2) Rethrow com cause
para contexto
try {
const data = await db.query(sql);
} catch (err) {
throw new DatabaseError('Erro ao executar consulta', { cause: err });
}
3) Erros customizados
class ValidationError extends Error {
constructor(message, details) {
super(message);
this.name = 'ValidationError';
this.details = details;
}
}
4) Tratamento em lote com Promise.allSettled
Quando várias promessas podem falhar independentemente, Promise.allSettled
permite continuar e inspecionar cada resultado sem abortar tudo com a primeira rejeição.
const results = await Promise.allSettled([op1(), op2(), op3()]);
results.forEach(r => {
if (r.status === 'rejected') console.error('Falha:', r.reason);
});
Usar allSettled
é uma alternativa a envolver tudo num único try
, quando cada operação é independente. (Ex.: chamadas paralelas a APIs distintas.)
Resumo rápido / Checklist
- Use
try...catch
para código que pode lançar. - No
catch
, trate somente o que conseguir — caso contrário, registre e rethrow. - Quando usar
await
, proteja comtry
para evitar rejeições não tratadas. - Adote
Error.cause
para encadear causas (ES2022). - Use Optional Catch Binding quando não precisar do objeto de erro (ES2019).
Comentários
Postar um comentário