Manejo de errores try…catch en JavaScript
Aprende el manejo de errores en JavaScript con try, catch, finally y throw. Cubre el objeto Error, tipos integrados, vinculación opcional, relanzamiento y limitaciones asíncronas.
Dominar el manejo de errores en JavaScript con Try...Catch
Manejar errores de forma eficaz es fundamental para crear aplicaciones robustas en JavaScript. Cuando algo falla en tiempo de ejecución — una llamada de red falla, un JSON está mal formado, una variable es undefined — JavaScript lanza una excepción. Sin un manejo adecuado, esa excepción detiene el script. Este artículo cubre la sentencia try...catch, la cláusula finally, el operador throw, el objeto Error y sus subtipos integrados, el relanzamiento de errores, y la limitación importante de que try...catch sincrónico no puede capturar errores lanzados dentro de callbacks asíncronos.
Entender Try...Catch en JavaScript
La sentencia try...catch es una herramienta para gestionar excepciones — errores que ocurren durante la ejecución del programa. Permite manejar estas excepciones de forma controlada en lugar de dejar que bloqueen todo el script.
El mecanismo tiene dos bloques:
try— el código que podría lanzar un error. JavaScript lo ejecuta normalmente.catch (error)— se ejecuta solo si algo en el bloquetrylanza un error. El valor lanzado se pasa comoerror.
Si no ocurre ningún error, el bloque catch se omite por completo. Si ocurre un error, la ejecución salta inmediatamente a catch — el resto del bloque try no se ejecuta.
Sintaxis básica de Try...Catch
A continuación se muestra un ejemplo sencillo para ilustrar la estructura básica de try...catch:
En este ejemplo, cualquier error que ocurra dentro del bloque try es capturado por el bloque catch, donde puede manejarse sin que el script se detenga.
Lanzar tus propios errores con throw
El operador throw genera una excepción. Puedes lanzar cualquier valor, pero la convención — y lo único que debes hacer en la práctica — es lanzar un objeto Error (o una instancia de alguno de sus subtipos). Hacerlo te proporciona automáticamente un message útil y un rastro de pila (stack).
Evita throw 'a string' o throw 42. Una cadena lanzada no tiene message, ni name, ni stack, por lo que el código que espera un objeto Error (como hace la mayoría) se comportará incorrectamente. Para errores específicos del dominio con campos adicionales, define tu propia clase — consulta errores personalizados, extender Error.
El objeto Error
Cuando haces new Error(message), obtienes un objeto con tres propiedades de uso común:
name— el tipo de error, por ejemplo"Error","TypeError","SyntaxError".message— la descripción legible que pasaste al constructor.stack— una cadena con la pila de llamadas en el momento en que se creó el error (no estándar pero compatible con todos los motores principales; muy útil para depurar, no para controlar el flujo).
Tipos de errores integrados
JavaScript incluye varias subclases de Error que el motor lanza automáticamente. Conocerlas te ayuda a escribir lógica de catch más precisa:
| Tipo | Se lanza cuando |
|---|---|
SyntaxError | El código o los datos están mal formados, por ejemplo JSON.parse() con JSON inválido. |
TypeError | Un valor no es del tipo esperado, por ejemplo al llamar a algo que no es una función o al leer una propiedad de undefined. |
ReferenceError | Se hace referencia a una variable que no existe. |
RangeError | Un valor está fuera de su rango permitido, por ejemplo una longitud de array inválida. |
URIError | decodeURIComponent() o similar recibe un URI malformado. |
EvalError | Histórico; raramente lanzado por los motores modernos. |
Cada uno tiene name establecido en su tipo, por lo que puedes bifurcar con instanceof:
Manejar errores específicos
También puedes manejar tipos específicos de errores examinando el objeto de error:
Este ejemplo maneja específicamente el SyntaxError que puede ocurrir durante el análisis de JSON. Si el error capturado es una instancia de SyntaxError, se gestiona registrando un mensaje específico. Si no lo es, el error se relanza, posiblemente para ser capturado por un manejador de errores de nivel superior o para detener el programa, indicando un escenario de error no manejado.
Relanzar errores
Un bloque catch captura todos los errores de su try, incluyendo aquellos que no sabes cómo manejar. El patrón recomendado es: inspeccionar el error, manejar los casos que conoces y relanzar todo lo demás para que se propague a un manejador externo. Silenciar errores desconocidos oculta bugs reales.
Vinculación opcional de catch
Si no necesitas el valor del error, puedes omitir el enlace por completo (ES2019+). Esto es útil cuando solo te importa el hecho de que algo falló:
Usar Finally
La cláusula finally se ejecuta después de los bloques try y catch, independientemente de si se lanzó o capturó una excepción. Es útil para liberar recursos o realizar tareas de limpieza, sin importar el resultado del try...catch:
Esto garantiza que el mensaje "Finally block executed" se registre tanto si ocurre un error como si no, demostrando cómo finally puede usarse para realizar las acciones de limpieza necesarias.
Ejemplos reales con la API
Usar la API JSONPlaceholder es una forma excelente de practicar el manejo de datos reales en JavaScript, especialmente al trabajar con peticiones asíncronas y gestionar posibles errores que puedan surgir durante estas operaciones. A continuación se presentan algunos ejemplos del mundo real usando la API JSONPlaceholder, que ofrece datos REST falsos en línea con los que puedes experimentar para pruebas y prototipos.
Ejemplo 1: Obtener publicaciones y manejar errores
En este ejemplo, obtenemos publicaciones de la API JSONPlaceholder usando fetch y manejamos posibles errores de red o problemas con la respuesta de la API:
Este script realiza una petición HTTP para recuperar un único elemento todo. Comprueba si la respuesta es exitosa (es decir, estado HTTP 200-299). Si no lo es, lanza un error con el estado de la respuesta. Cualquier error, ya sea por problemas de red o por la sentencia throw, es capturado en el bloque catch y registrado. El bloque finally se ejecuta independientemente del resultado, asegurando que se realicen las operaciones de limpieza o finales necesarias.
Ejemplo 2: Enviar datos y manejar excepciones
Aquí mostramos cómo enviar datos al servidor usando el método POST y manejar las excepciones de forma adecuada:
En este script, enviamos una nueva publicación al servidor. La función fetch se usa con el método POST, incluyendo cabeceras y un cuerpo serializado como JSON. Si la respuesta del servidor indica un fallo (estado HTTP no 2xx), se lanza un error que luego es capturado y manejado en el bloque catch. Independientemente del éxito o fallo, el bloque finally garantiza que la operación quede marcada como completada.
Ejemplo 3: Provocar y manejar un error deliberadamente
Este ejemplo solicita intencionadamente un ID de usuario que no existe en la API JSONPlaceholder, lo que provoca un error 404 Not Found que capturaremos y manejaremos.
Cómo funciona este ejemplo
- Endpoint de API inválido: Se llama a la función
fetchcon una URL que incluye un ID de usuario inválido (99999). Dado que JSONPlaceholder normalmente no tiene un usuario en ese índice, la API devolverá un error 404. - Verificar la validez de la respuesta: El código comprueba si el estado de la respuesta no está en el rango de éxito (200-299). Como el ID de usuario es inválido, la respuesta de la API será probablemente 404, activando el manejo de errores en la comprobación
if (!response.ok). - Lanzamiento del error: Dado que la respuesta no es correcta, se lanza un error con un mensaje que incluye el estado HTTP, que en este caso indicará un error 404 Not Found.
- Bloque catch: El bloque catch captura el error lanzado y registra un mensaje específico usando
console.log. Esto proporciona información clara sobre qué salió mal. - Bloque finally: Este bloque se usa para limpieza o sentencias finales, indicando la finalización del intento independientemente del resultado.
Por qué Try...Catch no puede capturar errores de callbacks asíncronos
Este es el error más común con try...catch. La sentencia es síncrona: solo captura errores lanzados mientras el bloque try se está ejecutando actualmente. Cuando programas un callback con setTimeout, un escuchador de eventos, o una promesa sin await, el callback se ejecuta más tarde — después de que try...catch ya ha terminado y la pila de llamadas está vacía. En ese momento no hay ningún try circundante que pueda capturar nada.
Para manejar el error, el try...catch debe estar dentro del callback, donde el error realmente se lanza:
La misma regla explica por qué try...catch funciona con async/await pero no con promesas sin await. await pausa la función y la reanuda en el mismo flujo lógico, por lo que una promesa rechazada aparece como un error lanzado que tu try puede capturar. Una promesa que no usas con await se resuelve de forma independiente y elude el try circundante — en ese caso debes usar .catch().
Para una cobertura más detallada del manejo asíncrono de errores, consulta Manejo de errores con promesas y async/await.
Conclusión
El manejo eficaz de errores en JavaScript es clave para desarrollar aplicaciones de alta calidad y resilientes. Usar try...catch te permite gestionar de forma controlada los errores síncronos y los rechazos con await, manteniendo el control sobre el flujo de la aplicación. Lanza objetos Error (nunca cadenas simples), bifurca sobre tipos integrados como TypeError y SyntaxError, relanza lo que no puedes manejar, y recuerda la limitación asíncrona: los errores en callbacks y promesas sin await necesitan su propio manejo.
Temas relacionados
- Errores personalizados, extender Error — define tus propias clases de error.
- Manejo de errores con promesas —
.catch()y flujo de rechazo. - Async/await —
try...catchcon código asíncrono. - Trabajar con JSON —
JSON.parsey elSyntaxErrorque puede lanzar.