"Eu aprendi muito mais com os meus erros do que com meus acertos." - "Thomas Edison"

Quando comecei a programar em C# logo me deparei com tratamento de exceções. Nessa época, eu achava ter entendido bem a utilização do Try e Catch, mas não tinha sacado que lance era aquele com o tal de Throw. Como pode alguém achar que entendeu try-catch sem entender também throw?

Pois é, ciente de que algumas peças não se encaixavam muito bem na minha cabeça, eu fiz o que sempre costumo fazer: investigar. Pesquisando. eu descobri 3 coisas:

  • Se você não sabe usar, é melhor não usar. Capturar uma exceção e não tratá-la corretamente é pior do que não capturá-la;
  • Tratamento de exceções poluem o código, tornando-o mais difícil de entender;
  • Tratamento de exceções diminuem a performance;

Por essas razões, eu fiquei um tempo sem utilizar tratamento de exceções, o que também não é recomendável, pois quando você o utiliza apropriadamente isso pode diminuir consideravelmente seu tempo com debugging.

Assim, para explorarmos com mais confiança o tratamento de erros em JavaScript(porque exceções são chamadas de erros na linguagem), vamos separar o assunto nos seguintes tópicos:

  • Erros em JavaScript
  • Vantagens de Lançar Erros
  • Quando Lançar Erros
  • Erros de Usuário e Erros de Desenvolvimento
  • Lançando Seus Próprios Erros

Erros em JavaScript

Em JavaScript, você pode lançar erros de qualquer tipo, mas o mais recomendável é que você utilize o próprio objeto Error ou crie seus próprios erros herdando dele.

Maneiras possíveis:

throw "ocorreu um erro";  
throw { message: "ocorreu um erro", solution: "conserte" };  
throw new Error( "ocorreu um erro" );  
throw new MyOwnError( "ocorreu um erro", "conserte" );  

Vantagens de Lançar Erros

Lançar erros permite que você forneça o texto que será mostrado pelo navegador. Ao invés, de apenas de números indicando a linha e a coluna, você pode incluir informações que tornem o problema mais identificável e fácil de resolver, como informar o nome da função na mensagem de erro e razão de ela ter falhado.

Quando Lançar Erros

Existem 3 regrinhas que podem ajudar a saber quando lançar erros:

  • Quando você tiver solucionado um bug que foi bastante difícil de resolver, adicione um erro customizável para lhe ajudar a mais rapidamente resolver o problema. Provavelmente, ele vai acontecer de novo.
  • Se você estiver codificando e pensando: "Poxa vida, eu espero que isso não aconteça, porque vai quebrar meu código".
  • Quando você tiver estiver disponibilizando código que será usado por outras pessoas que podem incorretamente utilizá-lo, então lance erros.

Uma das perguntas comuns é quando lançar erros(usar Throw) ou quando tratá-los(try-catch).

A resposta é que erros/exceções só deveriam ser lançados nas camadas mais inferiores da pilha de sua aplicação. Isso no contexto do desenvolvimento Front-End JavaScript normalmente significa que erros devem ser lançados em bibliotecas ou códigos seus que atuam como se fossem bibliotecas.

Considere o exemplo abaixo, em que você pretende criar uma função que recebe como parâmetro um elemento DOM e muda sua classe:

function isDomElement(){. Esse  
  ...
}

function changeElementClass(element, class){  
  if( !element || !isDomElement(element) ) {
    throw new Error("Deve ser passado um elemento DOM como parâmetro!");
  }
  this.element.class = class;
}

O exemplo acima se enquadra perfeitamente nas duas últimas regrinhas recomendadas e também poderia ser bastante difícil de rastrear, dependendo do contexto de sua utilização.

O tratamento de erros utilizando Try-Catch deve ser utilizado nas camadas mais superiores da lógica da aplicação e com cautela, pois é melhor que a exceção apareça o quanto antes que suprimi-la e perder o exato ponto de disparo do erro.

Normalmente, try-catch são utilizados em outra linguagens para conferir significado ao erro entre camadas. Exemplo:

Layer      Exception  
----------------------------
UI         DataNotFoundException  
Model      DatabaseRetrievalException  
DAO        SQLException  

Em Javascript, entretanto, eles podem ser utilizados para dar um feedback ao usuário da razão da aplicação não ter se comportado da maneira esperada, por exemplo.

Existe porém um dificultador que torna mais rara ainda a utilização de tratamentos try-catch em JavaScript, a natureza assíncrona da linguagem. O exemplo abaixo é problemático, pois não alerta sobre o erro da maneira esperada:

function funcaoQueGeraErro(){  
    var btn = document.getElementById('button');
    btn.style.backgroundColor = 'red';
    throw new Error("Um erro aconteceu!");
}

function invocacaoAssincrona(){  
    try{
        setTimeout(funcaoQueGeraErro, 1000);
    }catch(e){
        alert("Você não verá esse alerta de erro!")
    }
}

Uma maneira de solucionar o problema acima seria usando callbacks e essa é a maneira mais comum em JavaScript. Aqui você encontra a implementação no JSFiddle.

function funcaoQueGeraErro(callback){  
  try{
    var btn = document.getElementById('button');
    btn.style.backgroundColor = 'red';
    throw(new Error("Um erro aconteceu!"));
  }catch(e){
    callback(e);
  } 
}

function callbackErro(e){  
    //erro tratado
    console.log(e.message);
}

function invocacaoAssincrona(){  
    debugger;
    try{
        setTimeout(function(){
            funcaoQueGeraErro(callbackErro);
        }, 5000);
    }catch(e){
        alert("Não alerto, mas erro é lançado, por causa do callback");
    }
    console.log("cheguei antes de gerar erro");
}

Erros de Usuário e Erros de Desenvolvimento

Algumas pessoas confundem exceções com as mensagens mostradas ao usuário na tela.

Embora até se possa utilizar os objetos de erro com essa finalidade, é importante fazer a distinção entre os erros que são mostrados ao usuário e os erros que são voltados ao desenvolvedor.

Os erros causados por condições excepcionais normalmente são inseridos em arquivos de log ou no console do navegador, esses são os erros tema deste artigo. E são esses erros que tem maior relação com resolução de bugs.

Existem também os erros esperados da interação do usuário com a aplicação e esses não devem depender de tratamento ou lançamento de exceções. O mau preenchimento de um formulário, por exemplo, é um erro previsto e que deve retornar uma mensagem ao usuário sem precisar lançar ou tratar uma exceção.

Lançando Seus Próprios Erros

Lançar seus próprios erros é uma excelente prática para você distinguir suas próprias exceções da do browser e dar contexto ao desenvolvedor para que ele possa mais facilmente resolver o problema.

Segue um exemplo de como criar suas próprias exceções herdando do objeto nativo. Aqui você ver no JSFiddle uma implementação e como ela é disponibilizada no browser.

function MyError(message, solution, location) {  
    this.message = message + " Solution:" + solution +  " Location:" + location;
    this.solution = solution;
    this.location = location;
}

MyError.prototype = new Error();  
MyError.prototype.name = "My Error";  

Conclusão

Lançamento de erros é um pouco diferenciado em JavaScript, mas devem ser utilizados principalmente para facilitar a resolução de problemas. Você pode até não precisar em pequenas aplicações, mas imagine o caos que pode acontecer quando você disponibilizar uma API mal documentada e que constantemente gera problemas a terceiros desenvolvedores ou desenvolvedores de outra equipe que a utilizam.

Próximos Passos

Continue vendo boas práticas de JavaScript em:

Sobre o Autor

Johel Carvalho

Johel Carvalho

Engenheiro Civil formado pelo Instituto Militar de Engenharia (IME-RJ) em Dezembro de 2012. Largou a profissão pelo desenvolvimento web, começando com C# e sendo atualmente aficionado por JavaScript.

comments powered by Disqus