¡Hola desarrolladores junior! ![]()
Uno de los aspectos que más diferencia a un desarrollador junior de uno más experimentado es cómo maneja los errores. Aprender a anticipar, capturar y manejar errores hará que tu código sea mucho más confiable y profesional.
¿Por Qué es Importante Manejar Errores?
Imagina que tu aplicación se rompe cada vez que un usuario escribe un email inválido o cuando una API no responde. ¡Sería muy frustrante! El manejo adecuado de errores mejora la experiencia del usuario y facilita el debugging.
Tipos Comunes de Errores
1. Errores de Sintaxis
// ❌ Error de sintaxis - falta cerrar paréntesis
function saludar(nombre {
return `Hola ${nombre}`;
}
// ✅ Sintaxis correcta
function saludar(nombre) {
return `Hola ${nombre}`;
}
2. Errores de Referencia
// ❌ Variable no definida
console.log(usuarioNombre); // ReferenceError
// ✅ Verificar antes de usar
const usuarioNombre = "Ana";
console.log(usuarioNombre);
3. Errores de Tipo
// ❌ Intentar llamar un método en null/undefined
const usuario = null;
const nombre = usuario.nombre; // TypeError
// ✅ Verificación defensiva
const nombre = usuario?.nombre || 'Usuario desconocido';
Try-Catch: Tu Mejor Amigo
Uso Básico
try {
// Código que podría fallar
const datos = JSON.parse(jsonString);
console.log('Datos parseados:', datos);
} catch (error) {
// Qué hacer si algo sale mal
console.error('Error al parsear JSON:', error.message);
// Mostrar mensaje amigable al usuario
mostrarMensaje('Hubo un problema al procesar los datos');
}
Con Finally
function cargarDatos() {
mostrarIndicadorCarga(true);
try {
const datos = obtenerDatosDelServidor();
mostrarDatos(datos);
} catch (error) {
mostrarMensajeError('No se pudieron cargar los datos');
} finally {
// Esto SIEMPRE se ejecuta
mostrarIndicadorCarga(false);
}
}
Manejo de Errores en APIs
Fetch con Manejo Completo
async function obtenerUsuario(id) {
try {
mostrarCargando(true);
const response = await fetch(`/api/usuarios/${id}`);
// Verificar si la respuesta es exitosa
if (!response.ok) {
if (response.status === 404) {
throw new Error('Usuario no encontrado');
} else if (response.status === 500) {
throw new Error('Error del servidor');
} else {
throw new Error(`Error: ${response.status}`);
}
}
const usuario = await response.json();
return usuario;
} catch (error) {
console.error('Error al obtener usuario:', error);
// Mostrar mensaje específico según el error
if (error.message.includes('Failed to fetch')) {
mostrarError('Sin conexión a internet');
} else {
mostrarError(error.message);
}
return null;
} finally {
mostrarCargando(false);
}
}
Manejo de Timeouts
function fetchConTimeout(url, tiempoLimite = 5000) {
return Promise.race([
fetch(url),
new Promise((_, reject) =>
setTimeout(() => reject(new Error('Timeout')), tiempoLimite)
)
]);
}
// Uso
try {
const response = await fetchConTimeout('/api/datos', 3000);
const datos = await response.json();
} catch (error) {
if (error.message === 'Timeout') {
mostrarError('La solicitud tardó demasiado tiempo');
} else {
mostrarError('Error al cargar datos');
}
}
Validación de Formularios
Validación Robusta
function validarFormularioRegistro(datos) {
const errores = [];
// Validar email
if (!datos.email || !datos.email.trim()) {
errores.push('El email es requerido');
} else if (!esEmailValido(datos.email)) {
errores.push('El email no tiene un formato válido');
}
// Validar contraseña
if (!datos.password) {
errores.push('La contraseña es requerida');
} else if (datos.password.length < 6) {
errores.push('La contraseña debe tener al menos 6 caracteres');
}
// Validar edad
if (!datos.edad || isNaN(datos.edad)) {
errores.push('La edad debe ser un número válido');
} else if (datos.edad < 18) {
errores.push('Debes ser mayor de 18 años');
}
return {
esValido: errores.length === 0,
errores: errores
};
}
function esEmailValido(email) {
const regex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
return regex.test(email);
}
// Uso en formulario
document.getElementById('formulario').addEventListener('submit', function(e) {
e.preventDefault();
const datos = {
email: document.getElementById('email').value,
password: document.getElementById('password').value,
edad: parseInt(document.getElementById('edad').value)
};
const validacion = validarFormularioRegistro(datos);
if (validacion.esValido) {
enviarFormulario(datos);
} else {
mostrarErrores(validacion.errores);
}
});
Mostrar Errores de Forma Amigable
Funciones Utilitarias para UI
function mostrarError(mensaje, tipo = 'error') {
const contenedor = document.getElementById('mensajes');
const div = document.createElement('div');
div.className = `mensaje ${tipo}`;
div.textContent = mensaje;
contenedor.appendChild(div);
// Remover después de 5 segundos
setTimeout(() => {
div.remove();
}, 5000);
}
function mostrarCargando(mostrar) {
const indicador = document.getElementById('cargando');
indicador.style.display = mostrar ? 'block' : 'none';
}
function limpiarErrores() {
const errores = document.querySelectorAll('.mensaje.error');
errores.forEach(error => error.remove());
}
CSS para Mensajes
.mensaje {
padding: 12px;
margin: 8px 0;
border-radius: 4px;
font-weight: 500;
}
.mensaje.error {
background-color: #fee;
color: #c53030;
border: 1px solid #fed7d7;
}
.mensaje.exito {
background-color: #f0fff4;
color: #38a169;
border: 1px solid #c6f6d5;
}
.mensaje.advertencia {
background-color: #fffbf0;
color: #d69e2e;
border: 1px solid #feebc8;
}
Logging para Debugging
Sistema de Logs Básico
const Logger = {
info: (mensaje, datos = null) => {
console.log(`ℹ️ [INFO] ${mensaje}`, datos);
},
error: (mensaje, error = null) => {
console.error(`❌ [ERROR] ${mensaje}`, error);
// En producción, enviar a servicio de logs
},
warn: (mensaje, datos = null) => {
console.warn(`⚠️ [WARN] ${mensaje}`, datos);
},
debug: (mensaje, datos = null) => {
if (window.location.hostname === 'localhost') {
console.log(`🐛 [DEBUG] ${mensaje}`, datos);
}
}
};
// Uso
try {
Logger.info('Iniciando carga de usuarios');
const usuarios = await cargarUsuarios();
Logger.info('Usuarios cargados exitosamente', { cantidad: usuarios.length });
} catch (error) {
Logger.error('Error al cargar usuarios', error);
}
Mejores Prácticas
1. Sé Específico con los Errores
// ❌ Error genérico
throw new Error('Algo salió mal');
// ✅ Error específico
throw new Error('El email ya está registrado en el sistema');
2. No Ignores los Errores
// ❌ Ignorar errores silenciosamente
try {
operacionRiesgosa();
} catch (error) {
// No hacer nada es malo
}
// ✅ Manejar apropiadamente
try {
operacionRiesgosa();
} catch (error) {
Logger.error('Error en operación riesgosa', error);
mostrarMensajeAlUsuario('No se pudo completar la operación');
}
3. Usa Error Boundaries en React
class ErrorBoundary extends React.Component {
constructor(props) {
super(props);
this.state = { hasError: false };
}
static getDerivedStateFromError(error) {
return { hasError: true };
}
componentDidCatch(error, errorInfo) {
Logger.error('Error capturado por boundary', { error, errorInfo });
}
render() {
if (this.state.hasError) {
return <h2>Algo salió mal. Por favor, recarga la página.</h2>;
}
return this.props.children;
}
}
Ejercicio Práctico
Crea una función que:
- Haga una petición a una API
- Maneje diferentes tipos de errores (red, 404, 500, etc.)
- Muestre mensajes apropiados al usuario
- Registre errores para debugging
¡Intenta implementarlo y comparte tu código en los comentarios!
Resumen
- Siempre anticipa qué puede salir mal
- Usa try-catch para operaciones riesgosas
- Valida datos antes de procesarlos
- Muestra mensajes claros al usuario
- Registra errores para debugging
- No ignores errores nunca
El manejo de errores puede parecer tedioso al principio, pero es lo que separa aplicaciones amateur de aplicaciones profesionales. ¡Practiquen estas técnicas y verán la diferencia!
¿Qué tipo de errores les han causado más problemas? ¿Tienen alguna situación específica donde no saben cómo manejar un error? ¡Compartan sus experiencias!
juniordev #ErrorHandling bestpractices javascript webdev #LearningToCode