Volver a JavaScript Intermedio
JavaScript
JavaScript Intermedio
Manejo de Errores y Depuración
Un manejo robusto de errores distingue el código listo para producción del código de hobby.
Tipos de Error
// Tipos de error integrados
new Error('Error genérico');
new TypeError('Tipo incorrecto');
new RangeError('Fuera de rango');
new SyntaxError('Sintaxis inválida');
new ReferenceError('Variable no definida');
// Clases de error personalizadas
class ErrorApp extends Error {
constructor(mensaje, codigo, statusCode = 500) {
super(mensaje);
this.name = 'ErrorApp';
this.codigo = codigo;
this.statusCode = statusCode;
}
}
class ErrorNoEncontrado extends ErrorApp {
constructor(recurso) {
super(`${recurso} no encontrado`, 'NOT_FOUND', 404);
this.name = 'ErrorNoEncontrado';
}
}
throw new ErrorNoEncontrado('Usuario'); // ErrorNoEncontrado: Usuario no encontrado
Try/Catch/Finally
async function cargarUsuario(id) {
try {
const response = await fetch(`/api/usuarios/${id}`);
if (!response.ok) {
if (response.status === 404) throw new ErrorNoEncontrado('Usuario');
throw new ErrorApp(`HTTP ${response.status}`, 'HTTP_ERROR', response.status);
}
return await response.json();
} catch (err) {
if (err instanceof ErrorNoEncontrado) {
// Manejar específicamente
return null;
}
// Re-lanzar errores inesperados
throw err;
} finally {
// Siempre se ejecuta — ideal para limpieza
ocultarCargando();
}
}
Manejo Global de Errores
// Capturar errores síncronos no manejados
window.onerror = function (mensaje, fuente, linea, columna, error) {
registrarErrorEnServicio({ mensaje, fuente, linea, error });
return true; // Evita el manejo por defecto del navegador
};
// Capturar rechazos de promesas no manejados
window.addEventListener('unhandledrejection', event => {
registrarErrorEnServicio({ razón: event.reason });
event.preventDefault();
});
Patrón Result (Sin Excepciones)
Para flujos de error predecibles, retorna un objeto resultado en lugar de lanzar:
function dividir(a, b) {
if (b === 0) return { ok: false, error: 'División por cero' };
return { ok: true, valor: a / b };
}
const resultado = dividir(10, 0);
if (!resultado.ok) {
console.error(resultado.error);
} else {
console.log(resultado.valor);
}
Técnicas de Depuración
// Más descriptivo que console.log
console.group('Carga de usuario');
console.time('fetch');
const usuario = await obtenerUsuario(1);
console.timeEnd('fetch'); // "fetch: 234ms"
console.table(usuario); // Muestra en formato tabla
console.groupEnd();
// Punto de interrupción condicional
// En DevTools → pestaña Sources: clic derecho en breakpoint → Editar → añadir condición
// Perfilado de rendimiento
performance.mark('inicio-render');
renderizarListaCostosa();
performance.mark('fin-render');
performance.measure('render', 'inicio-render', 'fin-render');
const [medida] = performance.getEntriesByName('render');
console.log(`El render tardó ${medida.duration}ms`);
Patrón Error Boundary (Funcional)
const conManejoDeError = async (fn, fallback = null) => {
try {
return await fn();
} catch (err) {
console.error('Capturado:', err);
return fallback;
}
};
// Uso
const usuarios = await conManejoDeError(
() => fetch('/api/usuarios').then(r => r.json()),
[] // Retorna array vacío ante fallos
);