JavaScript de Cero a Experto / Manejo de errores y debugging
throw, try, catch, finally: la red de seguridad
En el módulo 10 usaste try/catch para atrapar promesas que fallaban. Hoy
lo ves completo y síncrono: cómo LANZAR un error a propósito cuando algo no
cuadra, cómo atraparlo sin que el programa muera, y qué hace ese finally
que siempre corre pase lo que pase.
El trapecista y la red
throw: levantar la mano
throw interrumpe el flujo en seco y "lanza hacia arriba" un valor —por
convención, un objeto Error. Nada después del throw, dentro de esa
función, se ejecuta:
Dos cosas cruciales: la línea después del dividir(10, 0) no se ejecuta
—throw corta el flujo ahí mismo—, y aun así el programa sobrevive porque
el catch recibió el golpe. Siempre lanza objetos Error (throw new Error(...)), no strings sueltos: un Error trae name, stack y todo el
parte del accidente de la lección 1. throw "texto" funciona, pero te roba
esa información.
finally: el que corre pase lo que pase
El bloque finally se ejecuta SIEMPRE: si todo salió bien, si hubo error,
incluso si hiciste return dentro del try. Es el lugar para lo que no
puede quedarse a medias —cerrar, limpiar, apagar un spinner de carga:
Mira cómo "cerrando recurso" aparece en AMBOS casos —el exitoso y el
fallido— incluso habiendo un return en el try y otro en el catch. Esa
es la promesa de finally: lo que pongas ahí corre sí o sí. Su uso real
favorito lo conociste en el módulo 10: apagar el estado "cargando..." de una
petición, ya sea que llegue la respuesta o que falle.
El pecado capital: el catch vacío
La trampa que ya conoces: lo asíncrono
Un try/catch síncrono no atrapa un error que ocurre "más tarde", dentro
de un setTimeout o una promesa sin await. Para cuando el error llega, el
try ya terminó hace rato —su red se guardó. Míralo con el orden de los
mensajes:
Fíjate en el orden de impresión (1 → 2 → 3): el console.log de afuera corre
ANTES que el timeout, prueba de que el try ya cerró cuando el callback
arranca. Por eso el catch de afuera es inútil para lo asíncrono, y la red
tiene que ir DENTRO del callback. En código async moderno usas async/await
con try/catch (módulo 10): el await "trae" el error de vuelta al try.
Regla mental: un try/catch solo cubre lo que pasa DENTRO de él, AHORA. Lo
que se agenda para después necesita su propia red.
Una función tiene un return dentro del try y también un bloque finally. Si el try hace return 'A', ¿corre el finally?
Mini-reto
Construye una red completa: 1) escribe raizSegura(n) que haga throw si
n es negativo ("No hay raíz real de un negativo") y devuelva
Math.sqrt(n) si no; 2) llámala dentro de un try/catch/finally con -9
y con 16, imprimiendo en el finally "cálculo terminado" en ambos
casos; 3) comprueba que el finally corre las dos veces y que el programa
no muere con el -9.
Qué sigue
Ya lanzas y atrapas errores genéricos. Pero un new Error("algo falló") es
pobre: no distingue un valor inválido de una falla de red. En la siguiente
lección creas tus PROPIOS tipos de error —con nombre y datos extra— usando
las clases del módulo 11. Cumplimos una promesa que quedó pendiente.