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