Pregunta 1¿Qué muestra try { console.log(1); } finally { console.log(2); }?
Capturar excepciones — try / catch / finally
Captura excepciones con try y catch, deja la limpieza en finally, relanza con throw y separa los casos según el tipo de error.
Cuando usas JSON.parse para convertir de nuevo en objeto una cadena que recibiste, basta un solo carácter mal puesto para que la ejecución se detenga en esa línea, y el código que muestra y guarda los datos, escrito más abajo, nunca llega a ejecutarse. Tampoco puedes descartar de antemano todas las causas posibles con comprobaciones if.
En este artículo verás try / catch, que captura la excepción que detuvo tu código, y finally, que se ejecuta siempre.
Capturar una excepción — try y catch
Imagina que quieres leer una cadena de configuración que llega del servidor y aplicarla a la página. Si la cadena está mal formada, JSON.parse lanza una excepción (un error que interrumpe la ejecución) en esa línea, y ninguna de las líneas de abajo se ejecuta. La página se queda en blanco y no pasa nada más.
Si se lanza una excepción dentro de try (un bloque que envuelve código que puede fallar), la ejecución salta a catch (un bloque que recibe la excepción). El error de catch (error) es solo el nombre que le das al valor recibido (funciona igual con err o con cualquier otro nombre). Contiene name, el nombre del tipo de error, y message, una descripción de lo que salió mal.
// Una cadena a la que le sobra una coma al final
const configText = '{"theme":"dark","fontSize":14,}';
try {
const config = JSON.parse(configText);
console.log(config.theme); // esta línea no se ejecuta
} catch (error) {
// si se lanza una excepción, la ejecución salta aquí
console.log("No se pudo cargar la configuración"); // No se pudo cargar la configuración
console.log(error.name); // SyntaxError
}
// como hay un catch, las líneas siguientes se ejecutan
console.log("Se muestra la configuración predeterminada"); // Se muestra la configuración predeterminada
Una vez que la ejecución pasa a catch, nunca vuelve para terminar la línea que falló, así que el mensaje alternativo o el valor predeterminado van dentro de catch. El texto de message cambia según el navegador; por eso, cuando necesites distinguir tipos de error, fíjate en name.
Ejecutar código tanto si sale bien como si falla — finally
Tareas de limpieza como ocultar un indicador de carga o cerrar una conexión abierta hacen falta tanto si la operación sale bien como si falla. Si escribes la misma línea en try y en catch, es fácil que más adelante corrijas una copia y te olvides de la otra, y los dos caminos dejan de comportarse igual.
finally (un bloque que se ejecuta siempre al salir de try) va después de catch. Tanto si try llegó hasta el final como si catch recibió una excepción, se ejecuta siempre justo antes de salir. También puedes omitir catch y escribir solo try y finally.
function loadReport(text) {
try {
const report = JSON.parse(text);
console.log(report.title);
} catch (error) {
console.log("No se pudo cargar");
} finally {
// se ejecuta siempre al salir de try
console.log("Indicador de carga oculto");
}
}
// Si sale bien
loadReport('{"title":"Ventas de septiembre"}'); // Ventas de septiembre → Indicador de carga oculto
// Si falla
loadReport('{"title":}'); // No se pudo cargar → Indicador de carga oculto
finally se ejecuta cuando termina el código de try o de catch. Por eso, en el código de arriba, el mensaje de limpieza aparece después del título si todo sale bien, y después del mensaje de error si algo falla.
Las variables declaradas dentro de try no se pueden leer fuera
Una variable declarada con const o let dentro de try solo se puede usar dentro de ese bloque. Si la lees desde catch, desde finally o desde cualquier línea que venga después de la sentencia try, obtienes un ReferenceError. Declara con let antes de try los valores que vayas a necesitar después, y dentro de try limítate a asignarles un valor.
Avisar a quien llama — throw dentro de catch
Imagina que una función que lee datos de reservas captura una excepción y se limita a registrarla. La función termina con normalidad, así que quien la llama no se entera del fallo, sigue usando el valor devuelto y vuelve a detenerse en otra línea, lejos de la causa real.
Si escribes throw (una sentencia que lanza una excepción) seguido del mismo error que recibió catch, esa excepción llega tal cual a quien llama. Así la función puede registrar el fallo por su cuenta y dejar que quien llama decida cómo responder.
function readEntry(text) {
try {
return JSON.parse(text);
} catch (error) {
console.log(`No se pueden leer los datos de la reserva: ${error.name}`);
throw error; // relanza tal cual la excepción recibida
}
}
try {
const entry = readEntry('{"name":"Carlos","seats":}');
console.log(entry.name); // esta línea no se ejecuta
} catch (error) {
console.log("Reserva cancelada"); // Reserva cancelada
}
Si quien llama también necesita reaccionar a una excepción capturada dentro de una función, relánzala escribiendo throw error; al final de catch. Las líneas que van después de throw no se ejecutan, así que pon antes la línea que registra el fallo.
Un catch vacío hace desaparecer el fallo
Si dejas vacío catch (error) { }, la excepción parece esfumarse, pero el fallo no queda registrado en ningún sitio y luego no puedes rastrear la causa. Lo más habitual es que la página se quede en blanco sin más. Haz siempre al menos una de estas cosas: mostrar un mensaje, recurrir a un valor predeterminado o relanzar.
Separar por tipo de error — instanceof y name
catch recibe todas las excepciones, sea cual sea su tipo. Pero el mensaje que quieres mostrar a los usuarios cambia según si los datos estaban mal formados o si faltaba un valor que intentabas leer.
instanceof (un operador que comprueba si el valor de la izquierda se creó a partir del tipo de la derecha) te permite comprobar el tipo, como en error instanceof SyntaxError. error.name también contiene el nombre del tipo como cadena.
const applicant = { name: "Ana", contact: null };
try {
console.log(applicant.contact.email);
} catch (error) {
if (error instanceof SyntaxError) {
console.log("El formato de los datos no es válido"); // aquí no llega
} else if (error instanceof TypeError) {
console.log("Falta el valor que intentaste leer"); // Falta el valor que intentaste leer
} else {
console.log(`Tipo de error inesperado: ${error.name}`);
}
console.log(error.name); // TypeError
}
catch (error), pero cada una tiene un name distinto. Si compruebas el tipo, puedes mostrar mensajes distintos.Las excepciones que no encajan con ninguna comprobación las recoge todas el else final. La tabla de abajo muestra cuatro tipos con los que te encontrarás a menudo y cuándo se lanza cada uno.
| Tipo | Cuándo se lanza | Código de ejemplo que lo lanza |
|---|---|---|
| SyntaxError | La cadena no tiene formato JSON | JSON.parse("{,}") |
| TypeError | Leíste una propiedad de null o undefined | applicant.contact.email |
| RangeError | Pasaste un valor fuera del rango permitido, como un número de dígitos | (1980).toFixed(200) (el máximo es 100) |
| ReferenceError | Leíste un nombre que nunca se declaró | console.log(total) |
Verificación de conocimientos
Responde cada pregunta una a una.
Pregunta 2Si el catch de una función solo registra el error y no incluye throw error;, ¿qué valor recibe quien la llama?
Pregunta 3¿Qué operador usas para comprobar el tipo del error que recibió catch?