1. ¿Qué son los Errores?
Los errores son problemas que ocurren durante la ejecución del código. Sin manejo adecuado, detienen la ejecución del programa.
Sin Manejo de Errores
function dividir(a, b) {
return a / b;
}
console.log(dividir(10, 2)); // 5
console.log(dividir(10, 0)); // Infinity ??
// Código problemático
const usuario = null;
console.log(usuario.nombre); // ? Error: Cannot read property 'nombre' of null
console.log('Este código nunca se ejecuta'); // No se ejecuta
Tipos de Errores Comunes
- SyntaxError: Error de sintaxis (código mal escrito)
- ReferenceError: Variable no definida
- TypeError: Tipo incorrecto (ej: null.propiedad)
- RangeError: Número fuera de rango
- URIError: Error en encodeURI/decodeURI
2. try...catch - Capturar Errores
try...catch permite "intentar" ejecutar código y capturar errores sin romper el programa.
Sintaxis Básica
try {
// Código que puede fallar
const usuario = null;
console.log(usuario.nombre);
} catch (error) {
// Se ejecuta SOLO si hay error
console.error('Ocurrió un error:', error.message);
}
console.log('El programa continúa'); // ? Se ejecuta
El Objeto Error
try {
const x = y; // 'y' no está definida
} catch (error) {
console.log('Nombre:', error.name); // "ReferenceError"
console.log('Mensaje:', error.message); // "y is not defined"
console.log('Stack:', error.stack); // Traza del error
}
finally - Siempre se Ejecuta
function procesarArchivo() {
let archivo = 'abierto';
try {
console.log('Procesando...');
throw new Error('Error al procesar');
console.log('Esto no se ejecuta');
} catch (error) {
console.log('Error capturado:', error.message);
} finally {
// Se ejecuta SIEMPRE (haya o no error)
console.log('Cerrando archivo...');
archivo = 'cerrado';
}
console.log('Archivo:', archivo); // "cerrado"
}
procesarArchivo();
// Procesando...
// Error capturado: Error al procesar
// Cerrando archivo...
// Archivo: cerrado
3. throw - Lanzar Errores
Puedes crear y lanzar tus propios errores con throw:
Lanzar Error Simple
function dividir(a, b) {
if (b === 0) {
throw new Error('No se puede dividir por cero');
}
return a / b;
}
try {
console.log(dividir(10, 2)); // 5
console.log(dividir(10, 0)); // Lanza error
} catch (error) {
console.error('Error:', error.message); // "No se puede dividir por cero"
}
Lanzar Diferentes Tipos de Errores
function validarEdad(edad) {
if (typeof edad !== 'number') {
throw new TypeError('La edad debe ser un número');
}
if (edad < 0 || edad > 150) {
throw new RangeError('Edad fuera de rango válido');
}
if (edad < 18) {
throw new Error('Debes ser mayor de edad');
}
return 'Edad válida';
}
try {
console.log(validarEdad('25')); // TypeError
// console.log(validarEdad(200)); // RangeError
// console.log(validarEdad(15)); // Error
} catch (error) {
if (error instanceof TypeError) {
console.log('Error de tipo:', error.message);
} else if (error instanceof RangeError) {
console.log('Error de rango:', error.message);
} else {
console.log('Error general:', error.message);
}
}
Lanzar Cualquier Valor
try {
throw 'String error';
// throw 404;
// throw { codigo: 500, mensaje: 'Error del servidor' };
} catch (error) {
console.log(error); // Captura cualquier cosa lanzada
}
4. Errores Person human alizados (Custom Errors)
Crea tus propias clases de error para mayor claridad:
Clase de Error Personalizada
class ErrorValidacion extends Error {
constructor(mensaje) {
super(mensaje);
this.name = 'ErrorValidacion';
}
}
class ErrorAutenticacion extends Error {
constructor(mensaje) {
super(mensaje);
this.name = 'ErrorAutenticacion';
this.codigo = 401;
}
}
function login(usuario, password) {
if (!usuario || !password) {
throw new ErrorValidacion('Usuario y contraseña son requeridos');
}
if (password.length < 8) {
throw new ErrorValidacion('La contraseña debe tener al menos 8 caracteres');
}
if (usuario !== 'admin' || password !== 'password123') {
throw new ErrorAutenticacion('Credenciales incorrectas');
}
return 'Login exitoso';
}
try {
console.log(login('admin', '123')); // Error
} catch (error) {
if (error instanceof ErrorValidacion) {
console.log('?? Validación:', error.message);
} else if (error instanceof ErrorAutenticacion) {
console.log('?? Auth error:', error.message, `(código ${error.codigo})`);
} else {
console.log('? Error desconocido:', error);
}
}
5. Manejo de Errores Asíncronos
Con Promesas (.catch)
function obtenerUsuario(id) {
return new Promise((resolve, reject) => {
if (id < 0) {
reject(new Error('ID inválido'));
}
setTimeout(() => {
resolve({ id, nombre: 'Usuario ' + id });
}, 1000);
});
}
obtenerUsuario(5)
.then(usuario => console.log(usuario))
.catch(error => console.error('Error:', error.message));
obtenerUsuario(-1)
.then(usuario => console.log(usuario))
.catch(error => console.error('Error capturado:', error.message));
Con Async/Await (try...catch)
async function cargarUsuario(id) {
try {
const usuario = await obtenerUsuario(id);
console.log('Usuario cargado:', usuario);
return usuario;
} catch (error) {
console.error('Error al cargar:', error.message);
return null;
}
}
cargarUsuario(5);
cargarUsuario(-1);
Fetch con Manejo de Errores
async function obtenerDatos(url) {
try {
const response = await fetch(url);
// fetch NO lanza error con códigos 404, 500, etc.
if (!response.ok) {
throw new Error(`HTTP ${response.status}: ${response.statusText}`);
}
const data = await response.json();
return data;
} catch (error) {
// Error de red o HTTP error
if (error.name === 'TypeError') {
console.error('Error de red:', error.message);
} else {
console.error('Error:', error.message);
}
return null;
}
}
obtenerDatos('https://jsonplaceholder.typicode.com/users/1');
obtenerDatos('https://api-inexistente.com/data');
6. Patrones de Manejo de Errores
1. Early Return (Retorno Temprano)
function procesarPedido(pedido) {
if (!pedido) {
throw new Error('Pedido inválido');
}
if (!pedido.items || pedido.items.length === 0) {
throw new Error('El pedido debe tener items');
}
if (pedido.total < 0) {
throw new Error('Total inválido');
}
// Lógica principal aquí
return 'Pedido procesado';
}
2. Error First Callback (Node.js style)
function leerArchivo(nombre, callback) {
setTimeout(() => {
if (!nombre) {
return callback(new Error('Nombre de archivo requerido'), null);
}
callback(null, 'Contenido del archivo');
}, 1000);
}
leerArchivo('documento.txt', (error, contenido) => {
if (error) {
console.error('Error:', error.message);
return;
}
console.log('Contenido:', contenido);
});
3. Result Object Pattern
function operacionSegura(valor) {
try {
if (valor < 0) {
throw new Error('Valor debe ser positivo');
}
return { success: true, data: valor * 2, error: null };
} catch (error) {
return { success: false, data: null, error: error.message };
}
}
const resultado1 = operacionSegura(5);
if (resultado1.success) {
console.log('Resultado:', resultado1.data); // 10
}
const resultado2 = operacionSegura(-5);
if (!resultado2.success) {
console.error('Error:', resultado2.error); // "Valor debe ser positivo"
}
4. Try-Catch Wrapper
// Envolver funciones async para manejo centralizado
function asyncHandler(fn) {
return async function(...args) {
try {
return await fn(...args);
} catch (error) {
console.error(`Error en ${fn.name}:`, error.message);
// Logging, notificación, etc.
throw error; // Re-lanzar si es necesario
}
};
}
const obtenerUsuarioSeguro = asyncHandler(async function obtenerUsuario(id) {
const response = await fetch(`https://api.example.com/users/${id}`);
return await response.json();
});
obtenerUsuarioSeguro(1);
7. Mejores Prácticas
? Hacer
- Usar nombres descriptivos para errores personalizados
- Incluir mensajes claros y accionables
- Capturar errores específicos cuando sea posible
- Limpiar recursos en
finally - Loggear errores para debugging
- Validar inputs temprano (fail fast)
? Evitar
- Catch vacíos que silencian errores
- Lanzar strings en vez de Error objects
- Ignorar errores en promesas
- Try-catch excesivo (solo donde sea necesario)
- Exponer información sensible en mensajes de error
Ejemplos
// ? MAL - Catch vacío
try {
funcionPeligrosa();
} catch (e) {
// Silencia el error - muy peligroso
}
// ? MAL - Lanzar strings
throw 'algo salió mal'; // Pierde stack trace
// ? BIEN - Error específico y descriptivo
if (!usuario.email) {
throw new ErrorValidacion('El email es requerido para crear usuario');
}
// ? BIEN - Logging antes de re-lanzar
try {
procesarDatos(datos);
} catch (error) {
console.error('Error al procesar:', error);
// Notificar a servicio de monitoreo
throw error; // Re-lanzar para que se maneje arriba
}
8. Debugging de Errores
1. Console Avanzado
try {
throw new Error('Error de prueba');
} catch (error) {
console.error(error); // Error completo
console.error(error.message); // Solo mensaje
console.error(error.stack); // Stack trace
console.table({ name: error.name, message: error.message });
}
2. Breakpoints con debugger
function funcionProblematica(x) {
if (x < 0) {
debugger; // El navegador se pausará aquí
throw new Error('Valor negativo');
}
return x * 2;
}
3. Capturar Errores No Manejados
// Errores síncronos globales
window.addEventListener('error', (event) => {
console.error('Error global:', event.error);
// Enviar a servicio de logging
});
// Promesas rechazadas no manejadas
window.addEventListener('unhandledrejection', (event) => {
console.error('Promesa no manejada:', event.reason);
event.preventDefault(); // Evitar que se muestre en consola
});
9. Ejercicios Prácticos
Ejercicio 1: Validador de Email
function validarEmail(email) {
// Debe lanzar TypeError si no es string
// Debe lanzar Error si está vacío
// Debe lanzar Error si no contiene '@'
// Debe retornar true si es válido
}
try {
console.log(validarEmail('test@example.com')); // true
console.log(validarEmail('invalido')); // Error
} catch (error) {
console.error(error.message);
}
Ejercicio 2: Función con Reintentos
async function intentarOperacion(operacion, intentos = 3) {
// Intenta ejecutar 'operacion' hasta 'intentos' veces
// Si falla todas las veces, lanza el último error
}
// Probar con una función que falla aleatoriamente
async function operacionInestable() {
if (Math.random() < 0.7) {
throw new Error('Falló');
}
return 'Éxito';
}
intentarOperacion(operacionInestable)
.then(resultado => console.log(resultado))
.catch(error => console.error('Falló después de 3 intentos'));
Resumen
- ?
try...catch...finallycaptura y maneja errores - ?
throwlanza errores (usanew Error()) - ? Crea errores personalizados con clases que extienden
Error - ? Async/await usa
try...catch, promesas usan.catch() - ?
finallyse ejecuta siempre (ideal para cleanup) - ? Valida inputs temprano, falla rápido
- ? Loggea errores para debugging
- ? No silencies errores con catch vacíos
- ? Diferencia errores esperados vs bugs