try/catch/finally e throw
Todo programa de verdade encontra o inesperado: uma API fora do ar, um dado no formato errado, uma conta que não deveria acontecer. try/catch é como você diz ao JavaScript: tente isto, mas se der errado, não quebre tudo, me avise.
Estudar esta lição interativa →Você já usou try/catch de relance, lá no fetch do Módulo 8, para lidar com uma API que podia estar fora do ar. Chegou a hora de entender essa ferramenta com profundidade, porque ela é a espinha dorsal de qualquer programa que precisa continuar funcionando mesmo quando algo dá errado. Pense numa função que calcula o frete de uma entrega: e se o CEP digitado for inválido? E se a API de frete não responder? Sem tratamento de erro, um problema desses derruba o programa inteiro. Com try/catch, você isola o risco.
A estrutura tem três partes, e cada uma tem um papel bem definido: o try ("tente") envolve o código que pode falhar; o catch ("capture") só roda se algo dentro do try der errado, e recebe o erro capturado; e o finally ("finalmente") roda sempre, tenha dado erro ou não, ótimo para uma limpeza que precisa acontecer de qualquer jeito (fechar uma conexão, esconder um "carregando").
// Um erro que o próprio JavaScript lança: ler um JSON quebrado.
function lerConfiguracao(texto) {
try {
const dados = JSON.parse(texto);
console.log("lido:", dados.tema);
} catch (erro) {
console.log("Capturado:", erro.name);
} finally {
console.log("Isto roda sempre, com erro ou sem erro.");
}
}
lerConfiguracao('{"tema": "escuro"}'); // dá certo: o catch não roda
lerConfiguracao('{ tema: escuro'); // dá errado: o catch captura o erroSó que um erro precisa existir para ser capturado, e nem todo erro acontece sozinho: às vezes é você quem detecta que algo está errado com a lógica do seu programa (um valor fora do esperado, uma regra de negócio violada) e precisa avisar o resto do código disso. Para isso existe o throw ("lançar"). Ele cria um objeto de erro (o mais comum é new Error("mensagem explicando o que houve")) e interrompe a execução na hora, saltando direto para o catch mais próximo que estiver "escutando" aquele trecho:
function dividir(a, b) {
if (b === 0) {
throw new Error("Não é possível dividir por zero");
}
return a / b;
}
try {
console.log(dividir(10, 2)); // roda normalmente
console.log(dividir(5, 0)); // lança o erro, pula o resto do try
console.log("esta linha nunca roda");
} catch (erro) {
console.log("Capturado:", erro.message);
}Rode: o throw interrompe o try, e a última linha dele nunca roda.
Repare que o objeto capturado no catch tem propriedades úteis: .message traz a mensagem que você escreveu, e .name traz o "tipo" do erro (por padrão, "Error"). E, unindo com o que você aprendeu no módulo passado sobre extends, dá para criar erros customizados, com um nome próprio, estendendo a classe Error nativa. Isso deixa o catch capaz de distinguir "este erro é de validação" de "este erro é outra coisa", tratando cada tipo do jeito certo:
// Uma classe de erro customizada, estendendo Error (Módulo 12: extends/super).
class ErroDeValidacao extends Error {
constructor(mensagem) {
super(mensagem);
this.name = "ErroDeValidacao";
}
}
function validarIdade(idade) {
if (idade < 0) {
throw new ErroDeValidacao("idade não pode ser negativa");
}
return idade;
}
try {
validarIdade(-5);
} catch (erro) {
console.log(erro.name + ":", erro.message);
console.log("é um ErroDeValidacao?", erro instanceof ErroDeValidacao);
}Erro customizado: o catch lê o name e confere o tipo com instanceof.
Um catch (erro) { } vazio, ou que só faz console.log("deu erro") sem olhar o que realmente aconteceu, é uma armadilha: ele engole qualquer problema, inclusive erros de programação de verdade (um typo, uma variável errada) que você preferia descobrir na hora, não escondidos atrás de um catch silencioso. Bom hábito: sempre que possível, olhe erro.message (ou erro.name, para erros customizados) e decida uma reação específica, em vez de um "engula e siga" genérico.
// Sua vez! Complete validarNota e trate o erro.
function validarNota(nota) {
// se nota < 0 ou nota > 10, lance: throw new Error("Nota fora do intervalo 0-10");
// senão, retorne a própria nota
}
try {
console.log(validarNota(15));
} catch (erro) {
console.log("Erro:", erro.message);
}Complete a validação e clique em Rodar.