voltar aos artigosadvanced topics
$cd~/artigos/error-handling-javascript-tratamento-erros
Advanced Topics
série 33 Conceitos JS·parte 31 de 38

Error Handling: Seu Código Precisa de um Plano B

22 minVanderlei José Alamino

"Não é sobre se algo vai dar errado. É sobre quando algo vai dar errado, e se você está preparado."

Erros acontecem — dados inválidos, rede instável, APIs inesperadas. Tratamento de erros é sua estratégia para detectar, responder e se recuperar com elegância.

snippetJavaScript
try {  const userData = JSON.parse(userInput);} catch (error) {  console.log('Não foi possível parsear:', error.message);}

Neste guia da série 33 Conceitos JS — projeto open source criado por Leonardo Maldonado — você aprende try...catch...finally, tipos de erro, throw, erros async e padrões de produção.

Pré-requisitos: Promises, Async/Await e Callbacks — tratamento async constrói sobre esses fundamentos.

error-handling-javascript-tratamento-erros.meta.jsonjson

// metadados do artigo

{
  "tag": "advanced topics",
  "readTime": "22 min",
  "author": "Vanderlei José Alamino",
  "source": "33jsconcepts.com",
  "series": "33 Conceitos JS",
  "part": {
    "current": 31,
    "total": 38
  }
}
abrir fonte original
error-handling-javascript-tratamento-erros.mdmarkdown

Fonte de referência

Conteúdo adaptado a partir do guia original em inglês.

33jsconcepts.com
01

seção

Analogia: O Trapézio do Circo

snippettext
try {     riskyMove() }     ← acrobata (código arriscado)catch {   recover()   }     ← rede de segurançafinally { cleanup()   }     ← show continua (sempre roda)
CircoJavaScriptPropósito
Ato de trapéziotryCódigo que pode falhar
RedecatchLida com o erro
Show continuafinallyCleanup incondicional
02

seção

try...catch...finally

snippetJavaScript
try {  const result = riskyOperation();  console.log(result);} catch (error) {  console.error('Algo deu errado:', error.message);} finally {  cleanup();  // SEMPRE roda — mesmo com return no try/catch}

try: execução pula para catch no primeiro erro. Linhas após o throw não rodam.

catch: recebe o objeto Error. ES2019+ permite catch { } sem parâmetro se não usar o erro.

finally: ideal para esconder spinners, fechar conexões, liberar recursos.

Armadilha: try/catch é síncrono

snippetJavaScript
// ❌ catch NÃO captura erro dentro de setTimeouttry {  setTimeout(() => { throw new Error('async'); }, 1000);} catch (e) { /* nunca roda */ } // ✓ try/catch DENTRO do callbacksetTimeout(() => {  try { throw new Error('async'); }  catch (e) { console.log('Capturado:', e.message); }}, 1000);
03

seção

O Objeto Error

PropriedadeDescrição
nameTipo — "TypeError", "SyntaxError"…
messageDescrição legível
stackCall stack (debug)
causeErro original (ES2022+)
snippetJavaScript
try {  undefinedVariable;} catch (error) {  console.log(error.name);     // ReferenceError  console.log(error.message);  // undefinedVariable is not defined  console.log(error.stack);    // stack trace completa}
04

seção

Tipos de Erro Built-in

TipoQuando ocorreExemplo
TypeErrorTipo erradonull.foo, chamar não-função
ReferenceErrorVariável inexistentetypo, import faltando
SyntaxErrorJSON/sintaxe inválidaJSON.parse('{ bad }')
RangeErrorFora do rangenew Array(-1)
URIErrorURI encodingdecodeURIComponent('%')
AggregateErrorMúltiplos errosPromise.any() todos rejeitam

TypeError — o mais comum. Prefira optional chaining: user?.name.

SyntaxError em JSON — runtime sim; erros de sintaxe no fonte são pegos em parse, não em try/catch.

05

seção

throw — Lance Sempre Error

snippetJavaScript
function divide(a, b) {  if (b === 0) throw new Error('Não pode dividir por zero');  return a / b;}
snippetJavaScript
// ❌ Sem stack tracethrow 'Algo deu errado';throw 404; // ✓ Com stack tracethrow new Error('Algo deu errado');throw new TypeError(`Esperava string, recebeu ${typeof value}`);

Mensagens boas dizem o quê deu errado e como consertar: "Email inválido: faltando @" em vez de "Input inválido".

06

seção

Classes de Erro Customizadas

snippetJavaScript
class AppError extends Error {  constructor(message, options) {    super(message, options);    this.name = this.constructor.name;  }} class ValidationError extends AppError {}class NetworkError extends AppError {  constructor(message, statusCode) {    super(message);    this.statusCode = statusCode;  }}

Use instanceof para ramificar tratamento:

snippetJavaScript
try {  await saveUser(userData);} catch (error) {  if (error instanceof ValidationError) showFieldErrors(error.fields);  else if (error instanceof NetworkError) showRetryButton();  else { console.error(error); showGenericError(); }}

Encadeamento com cause (ES2022+):

snippetJavaScript
throw new Error(`Falha ao carregar usuário ${userId}`, { cause: error });// error.cause.message → erro original do fetch
07

seção

Tratamento de Erros Async

Promises — .catch():

snippetJavaScript
fetch('/api/users')  .then(r => r.json())  .then(displayUsers)  .catch(err => console.error('Falha:', err))  .finally(() => hideSpinner());

async/await — try/catch:

snippetJavaScript
async function loadUsers() {  try {    const response = await fetch('/api/users');    return await response.json();  } catch (error) {    console.error(error);    throw error;  // re-lança se o chamador deve saber  }}

Armadilha #1: fetch() e response.ok

fetch() não lança em 404 ou 500 — só em falha de rede:

snippetJavaScript
const response = await fetch('/api/users/999');if (!response.ok) {  throw new Error(`HTTP ${response.status}`);}const user = await response.json();

Armadilha #2: forEach + async

Use for...of (sequencial) ou Promise.all (paralelo) — forEach ignora await corretamente.

08

seção

Handlers Globais

Rede de segurança de último recurso — não substituem try/catch local.

snippetJavaScript
window.onerror = (message, source, lineno, colno, error) => {  logErrorToService(error);  return true;}; window.addEventListener('unhandledrejection', event => {  logErrorToService(event.reason);  event.preventDefault();});

Use para Sentry/LogRocket em produção — nunca para engolir erros silenciosamente.

09

seção

Erros Comuns

  1. Catch vazio — erro perdido; no mínimo console.error.
  1. Captura ampla demais — esconde bugs; capture só erros esperados e re-lance o resto.
  1. Lançar strings — sem stack trace.
  1. Não re-lançar — chamador acha sucesso quando retorna undefined.
  1. Escopo de variável — declare let result fora do try se precisar depois:
snippetJavaScript
let result;try { result = riskyOperation(); }catch { result = fallback; }console.log(result);
10

seção

Padrões do Mundo Real

Retry com backoff exponencial:

snippetJavaScript
async function fetchWithRetry(url, retries = 3) {  for (let i = 0; i < retries; i++) {    try {      const r = await fetch(url);      if (!r.ok) throw new Error(`HTTP ${r.status}`);      return await r.json();    } catch (error) {      if (i === retries - 1) throw error;      await new Promise(res => setTimeout(res, 1000 * 2 ** i));    }  }}

ValidationError com múltiplos campos — colete todos os erros antes de lançar.

Graceful degradation — API → cache → defaults:

snippetJavaScript
async function loadPrefs(userId) {  try {    return await fetchFromApi(`/prefs/${userId}`);  } catch {    const cached = localStorage.getItem(`prefs_${userId}`);    if (cached) return JSON.parse(cached);    return { theme: 'light', language: 'pt' };  }}
11

seção

Perguntas Clássicas de Entrevista

12

seção

Teste Seu Conhecimento

$ summary --quick

Resumo rápido

  • try/catch/finally — capture síncrono; finally sempre roda
  • try/catch é síncrono — callbacks async precisam try interno ou .catch()
  • Sempre lance Error — stack trace para debug
  • fetch + response.ok — HTTP 4xx/5xx não lançam sozinhos
  • Classes customizadas — ValidationError, NetworkError + instanceof
  • error.cause — encadeie erros ao re-lançar com contexto
  • Não engula erros — catch vazio esconde bugs
  • Re-lance o que você não consegue tratar
  • Handlers globais — Sentry/unhandledrejection, não substituto local
  • Padrões — retry, validação agregada, graceful degradation

Créditos da série

Este artigo faz parte de uma série de estudos inspirada no projeto 33 Conceitos JS, criado por Leonardo Maldonado. Todo o conteúdo original está disponível em 33jsconcepts.com.