TechLead

Manejo Avanzado de Errores

Errores personalizados, error boundaries, manejadores globales y estrategias de depuración

Manejo Robusto de Errores

El manejo adecuado de errores es crucial para construir aplicaciones confiables. JavaScript proporciona mecanismos para capturar, crear y propagar errores.

Tipos de Error

  • Error — Tipo de error base
  • SyntaxError — Sintaxis de código inválida
  • ReferenceError — Referencia de variable inválida
  • TypeError — El valor es del tipo incorrecto
  • RangeError — Valor fuera del rango válido

try/catch/finally

try {
  const result = riskyOperation();
  console.log(result);
} catch (error) {
  console.error("Error:", error.message);
} finally {
  cleanup();
}

// Capturar tipos de error específicos
try {
  JSON.parse("json inválido");
} catch (error) {
  if (error instanceof SyntaxError) {
    console.log("JSON inválido");
  } else if (error instanceof TypeError) {
    console.log("Error de tipo");
  } else {
    throw error; // Re-lanzar errores desconocidos
  }
}

Clases de Error Personalizadas

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

class ValidationError extends AppError {
  constructor(message, field) {
    super(message, "VALIDATION_ERROR");
    this.field = field;
  }
}

class NotFoundError extends AppError {
  constructor(resource) {
    super(`${resource} no encontrado`, "NOT_FOUND");
    this.resource = resource;
  }
}

try {
  validateUser({ name: "Alice" });
} catch (error) {
  if (error instanceof ValidationError) {
    console.log(`Campo: ${error.field}, Mensaje: ${error.message}`);
  }
}

Manejo de Errores Asíncronos

// async/await - usa try/catch
async function loadUser(id) {
  try {
    const response = await fetch(`/api/users/${id}`);
    if (!response.ok) {
      throw new Error("Error al obtener usuario");
    }
    return await response.json();
  } catch (error) {
    console.error("Error inesperado:", error);
    throw error;
  }
}

// Wrapper para manejo consistente
async function tryCatch(promise) {
  try {
    const data = await promise;
    return [data, null];
  } catch (error) {
    return [null, error];
  }
}

const [user, error] = await tryCatch(fetchUser(1));
if (error) {
  handleError(error);
}

Reintento con Retroceso Exponencial

async function withRetry(fn, maxRetries = 3, delay = 1000) {
  let lastError;
  
  for (let attempt = 1; attempt <= maxRetries; attempt++) {
    try {
      return await fn();
    } catch (error) {
      lastError = error;
      if (attempt < maxRetries) {
        const waitTime = delay * Math.pow(2, attempt - 1);
        console.log(`Intento ${attempt} falló, reintentando en ${waitTime}ms`);
        await new Promise(r => setTimeout(r, waitTime));
      }
    }
  }
  throw lastError;
}

💡 Puntos Clave

  • • Crea clases de error personalizadas para errores específicos del dominio
  • • Usa try/catch para sync, .catch() o try/catch para async
  • • Configura manejadores globales para errores no capturados
  • • Registra errores en servicios externos (Sentry, LogRocket, etc.)
  • • Usa Error Boundaries en React para recuperación a nivel de componente