Tratamento de Erros em JavaScript: try/catch e Técnicas Avançadas em Node.js

Treinador Online de Python para Iniciantes

Aprenda Python facilmente sem sobrecarga teórica. Resolva tarefas práticas com verificação automática e escreva código diretamente no navegador.

Start Course

Tratamento de Erros em JavaScript: try/catch e Além: Nível Avançado



O tratamento de erros não é apenas uma proteção contra a queda da aplicação, mas um aspecto fundamental para construir sistemas confiáveis e tolerantes a falhas em JavaScript e Node.js. O uso básico de try/catch é familiar para todo desenvolvedor, mas em projetos reais, especialmente no lado do servidor, surgem muitas nuances: fluxos assíncronos, cadeias de promises, falhas globais e a necessidade de erros customizados estruturados. Neste artigo, vamos explorar técnicas avançadas de tratamento de erros que ajudarão você a escrever um código mais limpo e previsível em Node.js.



1. Mergulho Profundo em try/catch e Assincronicidade



O clássico try/catch é síncrono. Ele captura perfeitamente erros dentro de funções comuns, mas falha diante de callbacks assíncronos ou promises sem await. Em Node.js, onde 90% do código é assíncrono, isso frequentemente se torna a causa de exceções "engolidas".



Erro: try/catch não captura o erro em setTimeout

function dangerousAsync() {  setTimeout(() => {    throw new Error('Falha no timer!');  }, 1000);}

try { dangerousAsync();} catch (e) { console.log('Capturado:', e.message); // Este código NÃO será executado}


Neste exemplo, o erro é lançado fora do contexto do try, e o processo Node.js será encerrado abruptamente. A abordagem correta é usar promises ou async/await.



Solução: encapsulando o código assíncrono em uma Promise

function safeAsync() {  return new Promise((resolve, reject) => {    setTimeout(() => {      reject(new Error('Falha no timer!'));    }, 1000);  });}

(async () => { try { await safeAsync(); } catch (e) { console.log('Capturado:', e.message); // Será executado após 1 segundo }})();


A regra principal: encapsule qualquer operação assíncrona em uma promise e use await dentro de try/catch. Isso garante que o erro será capturado no contexto correto.



2. Classes de Erro Customizadas: Semântica e Contexto



Em vez de lançar new Error('Algo deu errado'), crie uma hierarquia de suas próprias classes de erro. Isso permite que, no nível do manipulador, você entenda o tipo de falha e reaja de forma adequada (por exemplo, registrar em log, enviar para monitoramento ou retornar um status HTTP específico ao usuário).



class AppError extends Error {  constructor(message, statusCode = 500) {    super(message);    this.name = this.constructor.name;    this.statusCode = statusCode;    Error.captureStackTrace(this, this.constructor);  }}

class ValidationError extends AppError { constructor(message) { super(message, 400); }}

class DatabaseError extends AppError { constructor(message, originalError) { super(message, 503); this.originalError = originalError; // Salva o erro original para depuração }}

// Usofunction findUser(id) { if (!id) throw new ValidationError('ID do usuário é obrigatório'); // ... lógica que pode lançar DatabaseError}


Vantagens desta abordagem:

  • Legibilidade: o nome da classe já indica a natureza do problema.
  • Roteamento: no manipulador global, você pode verificar instanceof e escolher a estratégia de resposta.
  • Campos adicionais: você pode adicionar quaisquer dados (statusCode, originalError, userId, etc.).


3. Manipuladores Globais de Erro em Node.js



Mesmo com o controle mais rigoroso, erros não tratados podem vazar. Em Node.js, existem dois eventos-chave para capturá-los: uncaughtException e unhandledRejection

Blogs

Book Recommendations