Una guía definitiva para manejar errores en JavaScript
Publicado: 2022-01-24La ley de Murphy establece que cualquier cosa que pueda salir mal eventualmente saldrá mal. Esto se aplica demasiado bien en el mundo de la programación. Si crea una aplicación, es probable que cree errores y otros problemas. ¡Los errores en JavaScript son uno de esos problemas comunes!
El éxito de un producto de software depende de qué tan bien sus creadores puedan resolver estos problemas antes de perjudicar a sus usuarios. Y JavaScript, de todos los lenguajes de programación, es conocido por su diseño promedio de manejo de errores.
Si está creando una aplicación de JavaScript, existe una alta probabilidad de que se equivoque con los tipos de datos en un momento u otro. Si no es así, entonces podría terminar reemplazando un indefinido con un operador nulo o triple igual ( ===
) con un operador doble igual ( ==
).
Es humano cometer errores. Es por eso que le mostraremos todo lo que necesita saber sobre el manejo de errores en JavaScript.
Este artículo lo guiará a través de los errores básicos en JavaScript y explicará los diversos errores que puede encontrar. A continuación, aprenderá a identificar y corregir estos errores. También hay un par de consejos para manejar los errores de manera efectiva en entornos de producción.
Sin más preámbulos, ¡comencemos!
¿Qué son los errores de JavaScript?
Los errores de programación se refieren a situaciones que no permiten que un programa funcione normalmente. Puede suceder cuando un programa no sabe cómo manejar el trabajo en cuestión, como cuando intenta abrir un archivo inexistente o se comunica con un punto final de API basado en la web mientras no hay conectividad de red.
Estas situaciones empujan al programa a arrojar errores al usuario, indicando que no sabe cómo proceder. El programa recopila la mayor cantidad de información posible sobre el error y luego informa que no puede avanzar.
Los programadores inteligentes intentan predecir y cubrir estos escenarios para que el usuario no tenga que descifrar un mensaje de error técnico como "404" de forma independiente. En cambio, muestran un mensaje mucho más comprensible: “No se pudo encontrar la página”.
Los errores en JavaScript son objetos que se muestran cada vez que ocurre un error de programación. Estos objetos contienen amplia información sobre el tipo de error, la declaración que causó el error y el seguimiento de la pila cuando ocurrió el error. JavaScript también permite a los programadores crear errores personalizados para proporcionar información adicional al depurar problemas.
Propiedades de un error
Ahora que la definición de un error de JavaScript está clara, es hora de profundizar en los detalles.
Los errores en JavaScript tienen ciertas propiedades estándar y personalizadas que ayudan a comprender la causa y los efectos del error. Por defecto, los errores en JavaScript contienen tres propiedades:
- mensaje : un valor de cadena que lleva el mensaje de error
- nombre : el tipo de error que ocurrió (profundizaremos en esto en la siguiente sección)
- stack : el seguimiento de la pila del código ejecutado cuando ocurrió el error.
Además, los errores también pueden tener propiedades como columnNumber, lineNumber, fileName, etc., para describir mejor el error. Sin embargo, estas propiedades no son estándar y pueden o no estar presentes en todos los objetos de error generados desde su aplicación de JavaScript.
Comprender el seguimiento de la pila
Un seguimiento de pila es la lista de llamadas a métodos en las que se encontraba un programa cuando ocurre un evento como una excepción o una advertencia. Así es como se ve un rastro de pila de muestra acompañado de una excepción:

Como puede ver, comienza imprimiendo el nombre y el mensaje del error, seguido de una lista de métodos que se estaban llamando. Cada llamada de método indica la ubicación de su código fuente y la línea en la que se invocó. Puede usar estos datos para navegar a través de su base de código e identificar qué fragmento de código está causando el error.
Esta lista de métodos está organizada de forma apilada. Muestra dónde se lanzó por primera vez su excepción y cómo se propagó a través de las llamadas a métodos apilados. La implementación de una captura para la excepción no permitirá que se propague a través de la pila y bloquee su programa. Sin embargo, es posible que desee dejar los errores fatales sin detectar para bloquear el programa en algunos escenarios intencionalmente.
Errores frente a excepciones
La mayoría de la gente suele considerar los errores y las excepciones como la misma cosa. Sin embargo, es esencial tener en cuenta una diferencia leve pero fundamental entre ellos.
Para entender esto mejor, tomemos un ejemplo rápido. Así es como puede definir un error en JavaScript:
const wrongTypeError = TypeError("Wrong type found, expected character")
Y así es como el objeto wrongTypeError
se convierte en una excepción:
throw wrongTypeError
Sin embargo, la mayoría de la gente tiende a usar la forma abreviada que define los objetos de error mientras los lanza:
throw TypeError("Wrong type found, expected character")
Esta es una práctica estándar. Sin embargo, es una de las razones por las que los desarrolladores tienden a mezclar excepciones y errores. Por lo tanto, conocer los fundamentos es vital, aunque use taquigrafía para hacer su trabajo rápidamente.
Tipos de errores en JavaScript
Hay una variedad de tipos de errores predefinidos en JavaScript. Son elegidos y definidos automáticamente por el tiempo de ejecución de JavaScript siempre que el programador no maneje explícitamente los errores en la aplicación.
Esta sección lo guiará a través de algunos de los tipos de errores más comunes en JavaScript y comprenderá cuándo y por qué ocurren.
RangeError
Se lanza un RangeError cuando una variable se establece con un valor fuera de su rango de valores legales. Por lo general, ocurre cuando se pasa un valor como argumento a una función y el valor dado no se encuentra en el rango de los parámetros de la función. A veces puede resultar complicado solucionarlo cuando se utilizan bibliotecas de terceros mal documentadas, ya que necesita conocer el rango de valores posibles para que los argumentos pasen el valor correcto.
Algunos de los escenarios comunes en los que se produce RangeError son:
- Intentando crear una matriz de longitudes ilegales a través del constructor Array.
- Pasar valores incorrectos a métodos numéricos como
toExponential()
,toPrecision()
,toFixed()
, etc. - Pasar valores ilegales a funciones de cadena como
normalize()
.
Error de referencia
Un ReferenceError ocurre cuando algo está mal con la referencia de una variable en su código. Es posible que haya olvidado definir un valor para la variable antes de usarla o que esté tratando de usar una variable inaccesible en su código. En cualquier caso, pasar por el seguimiento de la pila proporciona amplia información para encontrar y corregir la referencia de la variable que tiene la culpa.
Algunas de las razones comunes por las que se producen los errores de referencia son:
- Hacer un error tipográfico en un nombre de variable.
- Intentar acceder a variables de ámbito de bloque fuera de sus ámbitos.
- Hacer referencia a una variable global de una biblioteca externa (como $ de jQuery) antes de que se cargue.
Error de sintaxis
Estos errores son de los más sencillos de solucionar ya que indican un error en la sintaxis del código. Dado que JavaScript es un lenguaje de secuencias de comandos que se interpreta en lugar de compilar, estos se lanzan cuando la aplicación ejecuta la secuencia de comandos que contiene el error. En el caso de lenguajes compilados, dichos errores se identifican durante la compilación. Por lo tanto, los archivos binarios de la aplicación no se crean hasta que se corrigen.
Algunas de las razones comunes por las que pueden ocurrir SyntaxErrors son:
- Faltan comillas
- Faltan paréntesis de cierre
- Alineación incorrecta de llaves u otros caracteres
Es una buena práctica usar una herramienta de pelusa en su IDE para identificar dichos errores antes de que lleguen al navegador.
Error de tecleado
TypeError es uno de los errores más comunes en las aplicaciones de JavaScript. Este error se crea cuando algún valor no resulta ser de un tipo esperado en particular. Algunos de los casos comunes cuando ocurre son:
- Invocar objetos que no son métodos.
- Intentar acceder a las propiedades de objetos nulos o indefinidos
- Tratar una cadena como un número o viceversa
Hay muchas más posibilidades en las que puede ocurrir un TypeError. Veremos algunos casos famosos más adelante y aprenderemos a solucionarlos.
Error interno
El tipo InternalError se utiliza cuando se produce una excepción en el motor de tiempo de ejecución de JavaScript. Puede o no indicar un problema con su código.
La mayoría de las veces, InternalError ocurre solo en dos escenarios:
- Cuando un parche o una actualización del tiempo de ejecución de JavaScript tiene un error que arroja excepciones (esto sucede muy raramente)
- Cuando su código contiene entidades que son demasiado grandes para el motor de JavaScript (por ejemplo, demasiados casos de cambio, inicializadores de matriz demasiado grandes, demasiada recursividad)
El enfoque más apropiado para resolver este error es identificar la causa a través del mensaje de error y reestructurar la lógica de la aplicación, si es posible, para eliminar el aumento repentino de la carga de trabajo en el motor de JavaScript.
URIError
URIError ocurre cuando una función de manejo de URI global como decodeURIComponent
se usa ilegalmente. Por lo general, indica que el parámetro pasado a la llamada al método no se ajustaba a los estándares de URI y, por lo tanto, el método no lo analizó correctamente.
El diagnóstico de estos errores suele ser fácil, ya que solo necesita examinar los argumentos de malformación.
EvalError
Un EvalError ocurre cuando ocurre un error con una llamada a la función eval()
. La función eval()
se usa para ejecutar código JavaScript almacenado en cadenas. Sin embargo, dado que se desaconseja encarecidamente el uso de la función eval()
debido a problemas de seguridad y las especificaciones ECMAScript actuales ya no arrojan la clase EvalError
, este tipo de error existe simplemente para mantener la compatibilidad con versiones anteriores del código JavaScript heredado.
Si está trabajando en una versión anterior de JavaScript, es posible que encuentre este error. En cualquier caso, es mejor investigar el código ejecutado en la llamada a la función eval()
en busca de excepciones.
Creación de tipos de error personalizados
Si bien JavaScript ofrece una lista adecuada de clases de tipos de error para cubrir la mayoría de los escenarios, siempre puede crear un nuevo tipo de error si la lista no satisface sus requisitos. La base de esta flexibilidad radica en el hecho de que JavaScript te permite lanzar cualquier cosa literalmente con el comando throw
.
Entonces, técnicamente, estas declaraciones son completamente legales:
throw 8 throw "An error occurred"
Sin embargo, arrojar un tipo de datos primitivo no proporciona detalles sobre el error, como su tipo, nombre o el seguimiento de la pila que lo acompaña. Para corregir esto y estandarizar el proceso de manejo de errores, se ha proporcionado la clase Error
. También se desaconseja usar tipos de datos primitivos al generar excepciones.
Puede ampliar la clase de Error
para crear su clase de error personalizada. Aquí hay un ejemplo básico de cómo puedes hacer esto:
class ValidationError extends Error { constructor(message) { super(message); this.name = "ValidationError"; } }
Y puedes usarlo de la siguiente manera:
throw ValidationError("Property not found: name")
Y luego puede identificarlo usando la palabra clave instanceof
:
try { validateForm() // code that throws a ValidationError } catch (e) { if (e instanceof ValidationError) // do something else // do something else }
Los 10 errores más comunes en JavaScript
Ahora que comprende los tipos de errores comunes y cómo crear los personalizados, es hora de ver algunos de los errores más comunes que enfrentará al escribir código JavaScript.
1. RangeError no detectado
Este error ocurre en Google Chrome en algunos escenarios diferentes. Primero, puede suceder si llama a una función recursiva y no termina. Puedes comprobarlo tú mismo en Chrome Developer Console:

Entonces, para resolver tal error, asegúrese de definir correctamente los casos límite de su función recursiva. Otra razón por la que ocurre este error es si ha pasado un valor que está fuera del rango del parámetro de una función. Aquí hay un ejemplo:

El mensaje de error generalmente indicará qué está mal con su código. Una vez que realice los cambios, se resolverá.

2. TypeError no detectado: no se puede establecer la propiedad
Este error ocurre cuando establece una propiedad en una referencia indefinida. Puede reproducir el problema con este código:
var list list.count = 0
Este es el resultado que recibirá:

Para corregir este error, inicialice la referencia con un valor antes de acceder a sus propiedades. Así es como se ve cuando se arregla:

3. TypeError no capturado: no se puede leer la propiedad
Este es uno de los errores más frecuentes en JavaScript. Este error ocurre cuando intenta leer una propiedad o llamar a una función en un objeto indefinido. Puede reproducirlo muy fácilmente ejecutando el siguiente código en una consola de Chrome Developer:
var func func.call()
Aquí está la salida:

Un objeto indefinido es una de las muchas posibles causas de este error. Otra causa importante de este problema puede ser una inicialización incorrecta del estado al representar la interfaz de usuario. Aquí hay un ejemplo del mundo real de una aplicación React:
import React, { useState, useEffect } from "react"; const CardsList = () => { const [state, setState] = useState(); useEffect(() => { setTimeout(() => setState({ items: ["Card 1", "Card 2"] }), 2000); }, []); return ( <> {state.items.map((item) => ( <li key={item}>{item}</li> ))} </> ); }; export default CardsList;
La aplicación comienza con un contenedor de estado vacío y recibe algunos elementos después de un retraso de 2 segundos. El retardo se establece para imitar una llamada de red. Incluso si su red es súper rápida, aún enfrentará una pequeña demora debido a que el componente se procesará al menos una vez. Si intenta ejecutar esta aplicación, recibirá el siguiente error:

Esto se debe a que, en el momento de la representación, el contenedor de estado no está definido; por lo tanto, no existen items
de propiedad en él. Reparar este error es fácil. Solo necesita proporcionar un valor predeterminado inicial al contenedor de estado.
// ... const [state, setState] = useState({items: []}); // ...
Ahora, después del retraso establecido, su aplicación mostrará un resultado similar:

La solución exacta en su código puede ser diferente, pero la esencia aquí es siempre inicializar sus variables correctamente antes de usarlas.
4. TypeError: 'indefinido' no es un objeto
Este error ocurre en Safari cuando intenta acceder a las propiedades o llamar a un método en un objeto no definido. Puede ejecutar el mismo código anterior para reproducir el error usted mismo.

La solución a este error también es la misma: asegúrese de haber inicializado sus variables correctamente y que no estén indefinidas cuando se accede a una propiedad o método.
5. TypeError: nulo no es un objeto
Esto es, de nuevo, similar al error anterior. Ocurre en Safari, y la única diferencia entre los dos errores es que este se produce cuando el objeto cuya propiedad o método se accede es null
en lugar de undefined
. Puede reproducir esto ejecutando el siguiente fragmento de código:
var func = null func.call()
Este es el resultado que recibirá:

Dado que null
es un valor establecido explícitamente en una variable y JavaScript no lo asigna automáticamente. Este error puede ocurrir solo si está intentando acceder a una variable que usted mismo estableció como null
. Por lo tanto, debe revisar su código y verificar si la lógica que escribió es correcta o no.
6. TypeError: no se puede leer la propiedad 'longitud'
Este error ocurre en Chrome cuando intentas leer la longitud de un objeto null
o undefined
. La causa de este problema es similar a los problemas anteriores, pero ocurre con bastante frecuencia al manejar listas; por lo que merece una mención especial. Así es como puede reproducir el problema:

Sin embargo, en las versiones más recientes de Chrome, este error se informa como Uncaught TypeError: Cannot read properties of undefined
. Asi es como luce ahora:

La solución, nuevamente, es asegurarse de que el objeto a cuya longitud está tratando de acceder exista y no esté configurado como null
.
7. TypeError: 'indefinido' no es una función
Este error ocurre cuando intenta invocar un método que no existe en su secuencia de comandos, o existe, pero no se puede hacer referencia en el contexto de la llamada. Este error suele ocurrir en Google Chrome, y puedes solucionarlo comprobando la línea de código que arroja el error. Si encuentra un error tipográfico, arréglelo y verifique si resuelve su problema.
Si ha utilizado la palabra clave de autorreferencia this
en su código, este error podría surgir si this
está debidamente vinculado a su contexto. Considere el siguiente código:
function showAlert() { alert("message here") } document.addEventListener("click", () => { this.showAlert(); })
Si ejecuta el código anterior, arrojará el error que discutimos. Ocurre porque la función anónima pasada como detector de eventos se está ejecutando en el contexto del document
.
Por el contrario, la función showAlert
se define en el contexto de la window
.
Para resolver esto, debe pasar la referencia adecuada a la función vinculándola con el método bind()
:
document.addEventListener("click", this.showAlert.bind(this))
8. ReferenceError: el evento no está definido
Este error ocurre cuando intenta acceder a una referencia no definida en el alcance de la llamada. Esto suele suceder cuando se manejan eventos, ya que a menudo le brindan una referencia llamada event
en la función de devolución de llamada. Este error puede ocurrir si olvida definir el argumento del evento en los parámetros de su función o lo escribe mal.
Es posible que este error no ocurra en Internet Explorer o Google Chrome (ya que IE ofrece una variable de evento global y Chrome adjunta la variable de evento automáticamente al controlador), pero puede ocurrir en Firefox. Por lo tanto, es recomendable estar atento a errores tan pequeños.

9. TypeError: Asignación a variable constante
Este es un error que surge por descuido. Si intenta asignar un nuevo valor a una variable constante, se encontrará con este resultado:

Si bien parece fácil de arreglar en este momento, imagine cientos de declaraciones de variables de este tipo y una de ellas definida erróneamente como const
en lugar de let
. A diferencia de otros lenguajes de secuencias de comandos como PHP, existe una diferencia mínima entre el estilo de declaración de constantes y variables en JavaScript. Por lo tanto, es recomendable verificar sus declaraciones en primer lugar cuando se encuentre con este error. También podría encontrarse con este error si olvida que dicha referencia es una constante y la usa como una variable. Esto indica descuido o una falla en la lógica de su aplicación. Asegúrese de marcar esto cuando intente solucionar este problema.
10. (desconocido): error de secuencia de comandos
Un error de secuencia de comandos ocurre cuando una secuencia de comandos de terceros envía un error a su navegador. Este error va seguido de (desconocido) porque la secuencia de comandos de terceros pertenece a un dominio diferente al de su aplicación. El navegador oculta otros detalles para evitar la filtración de información confidencial del script de terceros.
No puede resolver este error sin conocer los detalles completos. Esto es lo que puede hacer para obtener más información sobre el error:
- Agregue el atributo
crossorigin
en la etiqueta del script. - Establezca el encabezado
Access-Control-Allow-Origin
correcto en el servidor que aloja el script. - [Opcional] Si no tiene acceso al servidor que aloja la secuencia de comandos, puede considerar usar un proxy para transmitir su solicitud al servidor y al cliente con los encabezados correctos.
Una vez que pueda acceder a los detalles del error, puede establecerse para solucionar el problema, que probablemente estará en la biblioteca de terceros o en la red.
Cómo identificar y prevenir errores en JavaScript
Si bien los errores discutidos anteriormente son los más comunes y frecuentes en JavaScript, se encontrará con que confiar en algunos ejemplos nunca puede ser suficiente. Es vital comprender cómo detectar y prevenir cualquier tipo de error en una aplicación de JavaScript mientras se desarrolla. Así es como puede manejar los errores en JavaScript.
Lanzar y atrapar errores manualmente
La forma más fundamental de manejar los errores que se han producido manualmente o por el tiempo de ejecución es detectarlos. Como la mayoría de los otros lenguajes, JavaScript ofrece un conjunto de palabras clave para manejar errores. Es esencial conocer cada uno de ellos en profundidad antes de comenzar a manejar los errores en su aplicación de JavaScript.
tirar
La primera y más básica palabra clave del conjunto es throw
. Como es evidente, la palabra clave throw se utiliza para generar errores para crear excepciones en el tiempo de ejecución de JavaScript de forma manual. Ya hemos discutido esto anteriormente en el artículo, y aquí está la esencia del significado de esta palabra clave:
- Puede
throw
cualquier cosa, incluidos números, cadenas y objetos deError
. - Sin embargo, no es recomendable arrojar tipos de datos primitivos, como cadenas y números, ya que no contienen información de depuración sobre los errores.
- Ejemplo:
throw TypeError("Please provide a string")
tratar
La palabra clave try
se usa para indicar que un bloque de código podría generar una excepción. Su sintaxis es:
try { // error-prone code here }
Es importante tener en cuenta que un bloque catch
siempre debe seguir al bloque try
para manejar los errores de manera efectiva.
captura
La palabra clave catch
se utiliza para crear un bloque catch. Este bloque de código es responsable de manejar los errores que detecta el bloque de try
final. Aquí está su sintaxis:
catch (exception) { // code to handle the exception here }
Y así es como implementas los bloques try
y catch
juntos:
try { // business logic code } catch (exception) { // error handling code }
A diferencia de C++ o Java, no puede agregar varios bloques catch
a un bloque try
en JavaScript. Esto significa que no puedes hacer esto:
try { // business logic code } catch (exception) { if (exception instanceof TypeError) { // do something } } catch (exception) { if (exception instanceof RangeError) { // do something } }
En su lugar, puede usar una instrucción if...else
o una instrucción switch case dentro del bloque catch único para manejar todos los casos de error posibles. Se vería así:
try { // business logic code } catch (exception) { if (exception instanceof TypeError) { // do something } else if (exception instanceof RangeError) { // do something else } }
por fin
La palabra clave finally
se usa para definir un bloque de código que se ejecuta después de que se ha manejado un error. Este bloque se ejecuta después de los bloques try y catch.
Además, el bloque finalmente se ejecutará independientemente del resultado de los otros dos bloques. Esto significa que incluso si el bloque catch no puede manejar el error por completo o si se arroja un error en el bloque catch, el intérprete ejecutará el código en el último bloque antes de que el programa se bloquee.
Para que se considere válido, el bloque de prueba en JavaScript debe ir seguido de un bloque de captura o finalmente. Sin ninguno de ellos, el intérprete generará un SyntaxError. Por lo tanto, asegúrese de seguir sus bloques de prueba con al menos cualquiera de ellos cuando maneje errores.
Manejar errores globalmente con el método onerror()
El método onerror()
está disponible para todos los elementos HTML para manejar cualquier error que pueda ocurrir con ellos. Por ejemplo, si una etiqueta img
no puede encontrar la imagen cuya URL se especifica, activa su método onerror para permitir que el usuario maneje el error.
Por lo general, proporcionaría otra URL de imagen en la llamada onerror para que la etiqueta img
recurra. Así es como puedes hacerlo a través de JavaScript:
const image = document.querySelector("img") image.onerror = (event) => { console.log("Error occurred: " + event) }
Sin embargo, puede usar esta característica para crear un mecanismo global de manejo de errores para su aplicación. Así es como puedes hacerlo:
window.onerror = (event) => { console.log("Error occurred: " + event) }
Con este controlador de eventos, puede deshacerse de los múltiples bloques try...catch
que se encuentran en su código y centralizar el manejo de errores de su aplicación de manera similar al manejo de eventos. Puede adjuntar varios controladores de errores a la ventana para mantener el principio de responsabilidad única de los principios de diseño de SOLID. El intérprete recorrerá todos los controladores hasta que llegue al adecuado.
Pasar errores a través de devoluciones de llamada
Si bien las funciones simples y lineales permiten que el manejo de errores siga siendo simple, las devoluciones de llamadas pueden complicar el asunto.
Considere la siguiente pieza de código:
¿Necesita una solución de hospedaje que le brinde una ventaja competitiva? Kinsta lo tiene cubierto con una velocidad increíble, seguridad de última generación y escalado automático. Consulta nuestros planes
const calculateCube = (number, callback) => { setTimeout(() => { const cube = number * number * number callback(cube) }, 1000) } const callback = result => console.log(result) calculateCube(4, callback)
La función anterior demuestra una condición asincrónica en la que una función tarda un tiempo en procesar las operaciones y devuelve el resultado más tarde con la ayuda de una devolución de llamada.
Si intenta ingresar una cadena en lugar de 4 en la llamada de función, obtendrá NaN
como resultado.
Esto debe manejarse adecuadamente. Así es cómo:
const calculateCube = (number, callback) => { setTimeout(() => { if (typeof number !== "number") throw new Error("Numeric argument is expected") const cube = number * number * number callback(cube) }, 1000) } const callback = result => console.log(result) try { calculateCube(4, callback) } catch (e) { console.log(e) }
Esto debería resolver el problema idealmente. Sin embargo, si intenta pasar una cadena a la llamada de función, recibirá esto:

Aunque haya implementado un bloque try-catch al llamar a la función, aún dice que el error no se detectó. El error se produce después de que se haya ejecutado el bloque catch debido al retraso del tiempo de espera.
Esto puede ocurrir rápidamente en las llamadas de la red, donde se producen retrasos inesperados. Debe cubrir estos casos mientras desarrolla su aplicación.
Así es como puede manejar los errores correctamente en las devoluciones de llamada:
const calculateCube = (number, callback) => { setTimeout(() => { if (typeof number !== "number") { callback(new TypeError("Numeric argument is expected")) return } const cube = number * number * number callback(null, cube) }, 2000) } const callback = (error, result) => { if (error !== null) { console.log(error) return } console.log(result) } try { calculateCube('hey', callback) } catch (e) { console.log(e) }
Ahora, la salida en la consola será:

Esto indica que el error se ha manejado adecuadamente.
Manejar errores en promesas
La mayoría de las personas tienden a preferir las promesas para manejar actividades asincrónicas. Las promesas tienen otra ventaja: una promesa rechazada no finaliza su script. Sin embargo, aún necesita implementar un bloque catch para manejar los errores en las promesas. Para entender esto mejor, reescribamos la función de calculateCube()
usando Promesas:
const delay = ms => new Promise(res => setTimeout(res, ms)); const calculateCube = async (number) => { if (typeof number !== "number") throw Error("Numeric argument is expected") await delay(5000) const cube = number * number * number return cube } try { calculateCube(4).then(r => console.log(r)) } catch (e) { console.log(e) }
El tiempo de espera del código anterior se ha aislado en la función de delay
para su comprensión. Si intenta ingresar una cadena en lugar de 4, el resultado que obtendrá será similar a este:

Nuevamente, esto se debe a que Promise
arroja el error después de que todo lo demás haya completado la ejecución. La solución a este problema es simple. Simplemente agregue una llamada catch()
a la cadena de promesas como esta:
calculateCube("hey") .then(r => console.log(r)) .catch(e => console.log(e))
Ahora la salida será:

Puede observar lo fácil que es manejar errores con promesas. Además, puede encadenar un bloque finally()
y la llamada de promesa para agregar código que se ejecutará después de que se haya completado el manejo de errores.
Alternativamente, también puede manejar los errores en las promesas usando la técnica tradicional de intentar-atrapar-finalmente. Así es como se vería tu llamada de promesa en ese caso:
try { let result = await calculateCube("hey") console.log(result) } catch (e) { console.log(e) } finally { console.log('Finally executed") }
Sin embargo, esto funciona solo dentro de una función asíncrona. Por lo tanto, la forma preferida de manejar los errores en las promesas es encadenar la catch
y, finally
, la llamada de la promesa.
throw/catch vs onerror() vs Callbacks vs Promises: ¿Cuál es el mejor?
Con cuatro métodos a su disposición, debe saber elegir el más adecuado en cualquier caso de uso. Así es como pueden decidir por sí mismos:
lanzar/atrapar
Usará este método la mayor parte del tiempo. Asegúrese de implementar condiciones para todos los errores posibles dentro de su bloque catch y recuerde incluir un bloque finalmente si necesita ejecutar algunas rutinas de limpieza de memoria después del bloque try.
Sin embargo, demasiados bloques try/catch pueden hacer que su código sea difícil de mantener. Si se encuentra en tal situación, es posible que desee manejar los errores a través del controlador global o el método de promesa.
Al decidir entre los bloques try/catch asincrónicos y catch()
de la promesa, es recomendable optar por los bloques try/catch asíncronos, ya que harán que su código sea lineal y fácil de depurar.
onerror()
Es mejor usar el método onerror()
cuando sabe que su aplicación tiene que manejar muchos errores y pueden estar bien dispersos en la base de código. El método onerror
le permite manejar los errores como si fueran un evento más manejado por su aplicación. Puede definir varios controladores de errores y adjuntarlos a la ventana de su aplicación en la representación inicial.
Sin embargo, también debe recordar que el método onerror()
puede ser innecesariamente difícil de configurar en proyectos más pequeños con un menor margen de error. Si está seguro de que su aplicación no arrojará demasiados errores, el método tradicional de lanzar/atrapar funcionará mejor para usted.
Devoluciones de llamadas y promesas
El manejo de errores en devoluciones de llamada y promesas difiere debido a su diseño y estructura de código. Sin embargo, si elige entre estos dos antes de haber escrito su código, sería mejor seguir con las promesas.
Esto se debe a que las promesas tienen una construcción incorporada para encadenar un bloque catch()
y un bloque finally()
para manejar los errores fácilmente. Este método es más fácil y limpio que definir argumentos adicionales/reutilizar argumentos existentes para manejar errores.
Keep Track of Changes With Git Repositories
Many errors often arise due to manual mistakes in the codebase. While developing or debugging your code, you might end up making unnecessary changes that may cause new errors to appear in your codebase. Automated testing is a great way to keep your code in check after every change. However, it can only tell you if something's wrong. If you don't take frequent backups of your code, you'll end up wasting time trying to fix a function or a script that was working just fine before.
This is where git plays its role. With a proper commit strategy, you can use your git history as a backup system to view your code as it evolved through the development. You can easily browse through your older commits and find out the version of the function working fine before but throwing errors after an unrelated change.
You can then restore the old code or compare the two versions to determine what went wrong. Modern web development tools like GitHub Desktop or GitKraken help you to visualize these changes side by side and figure out the mistakes quickly.
A habit that can help you make fewer errors is running code reviews whenever you make a significant change to your code. If you're working in a team, you can create a pull request and have a team member review it thoroughly. This will help you use a second pair of eyes to spot out any errors that might have slipped by you.
Best Practices for Handling Errors in JavaScript
The above-mentioned methods are adequate to help you design a robust error handling approach for your next JavaScript application. However, it would be best to keep a few things in mind while implementing them to get the best out of your error-proofing. Here are some tips to help you.
1. Use Custom Errors When Handling Operational Exceptions
We introduced custom errors early in this guide to give you an idea of how to customize the error handling to your application's unique case. It's advisable to use custom errors wherever possible instead of the generic Error
class as it provides more contextual information to the calling environment about the error.
On top of that, custom errors allow you to moderate how an error is displayed to the calling environment. This means that you can choose to hide specific details or display additional information about the error as and when you wish.
You can go so far as to format the error contents according to your needs. This gives you better control over how the error is interpreted and handled.
2. Do Not Swallow Any Exceptions
Even the most senior developers often make a rookie mistake — consuming exceptions levels deep down in their code.
You might come across situations where you have a piece of code that is optional to run. If it works, great; if it doesn't, you don't need to do anything about it.
In these cases, it's often tempting to put this code in a try block and attach an empty catch block to it. However, by doing this, you'll leave that piece of code open to causing any kind of error and getting away with it. This can become dangerous if you have a large codebase and many instances of such poor error management constructs.
The best way to handle exceptions is to determine a level on which all of them will be dealt and raise them until there. This level can be a controller (in an MVC architecture app) or a middleware (in a traditional server-oriented app).
This way, you'll get to know where you can find all the errors occurring in your app and choose how to resolve them, even if it means not doing anything about them.
3. Use a Centralized Strategy for Logs and Error Alerts
Logging an error is often an integral part of handling it. Those who fail to develop a centralized strategy for logging errors may miss out on valuable information about their app's usage.
An app's event logs can help you figure out crucial data about errors and help to debug them quickly. If you have proper alerting mechanisms set up in your app, you can know when an error occurs in your app before it reaches a large section of your user base.
It's advisable to use a pre-built logger or create one to suit your needs. You can configure this logger to handle errors based on their levels (warning, debug, info, etc.), and some loggers even go so far as to send logs to remote logging servers immediately. This way, you can watch how your application's logic performs with active users.
4. Notify Users About Errors Appropriately
Another good point to keep in mind while defining your error handling strategy is to keep the user in mind.
All errors that interfere with the normal functioning of your app must present a visible alert to the user to notify them that something went wrong so the user can try to work out a solution. If you know a quick fix for the error, such as retrying an operation or logging out and logging back in, make sure to mention it in the alert to help fix the user experience in real-time.
In the case of errors that don't cause any interference with the everyday user experience, you can consider suppressing the alert and logging the error to a remote server for resolving later.
5. Implement a Middleware (Node.js)
The Node.js environment supports middlewares to add functionalities to server applications. You can use this feature to create an error-handling middleware for your server.
The most significant benefit of using middleware is that all of your errors are handled centrally in one place. You can choose to enable/disable this setup for testing purposes easily.
Here's how you can create a basic middleware:
const logError = err => { console.log("ERROR: " + String(err)) } const errorLoggerMiddleware = (err, req, res, next) => { logError(err) next(err) } const returnErrorMiddleware = (err, req, res, next) => { res.status(err.statusCode || 500) .send(err.message) } module.exports = { logError, errorLoggerMiddleware, returnErrorMiddleware }
Luego puede usar este middleware en su aplicación de esta manera:
const { errorLoggerMiddleware, returnErrorMiddleware } = require('./errorMiddleware') app.use(errorLoggerMiddleware) app.use(returnErrorMiddleware)
Ahora puede definir una lógica personalizada dentro del middleware para manejar los errores de manera adecuada. Ya no necesita preocuparse por implementar construcciones de manejo de errores individuales en su base de código.
6. Reinicie su aplicación para manejar los errores del programador (Node.js)
Cuando las aplicaciones de Node.js encuentran errores del programador, es posible que no generen necesariamente una excepción e intenten cerrar la aplicación. Dichos errores pueden incluir problemas derivados de errores del programador, como un alto consumo de CPU, una sobrecarga de memoria o pérdidas de memoria. La mejor manera de manejar esto es reiniciar correctamente la aplicación bloqueándola a través del modo de clúster de Node.js o una herramienta única como PM2. Esto puede garantizar que la aplicación no se bloquee con la acción del usuario, presentando una experiencia de usuario terrible.
7. Captura todas las excepciones no detectadas (Node.js)
Nunca puede estar seguro de haber cubierto todos los posibles errores que pueden ocurrir en su aplicación. Por lo tanto, es esencial implementar una estrategia alternativa para capturar todas las excepciones no detectadas de su aplicación.
Así es como puedes hacer eso:
process.on('uncaughtException', error => { console.log("ERROR: " + String(error)) // other handling mechanisms })
También puede identificar si el error que ocurrió es una excepción estándar o un error operativo personalizado. Según el resultado, puede salir del proceso y reiniciarlo para evitar un comportamiento inesperado.
8. Captura todos los rechazos de promesas no manejados (Node.js)
De manera similar a cómo nunca puede cubrir todas las posibles excepciones, existe una alta probabilidad de que se pierda el manejo de todos los posibles rechazos de promesas. Sin embargo, a diferencia de las excepciones, los rechazos de promesas no arrojan errores.
Por lo tanto, una promesa importante que fue rechazada podría pasar desapercibida como una advertencia y dejar su aplicación abierta a la posibilidad de encontrarse con un comportamiento inesperado. Por lo tanto, es crucial implementar un mecanismo alternativo para manejar el rechazo de promesas.
Así es como puedes hacer eso:
const promiseRejectionCallback = error => { console.log("PROMISE REJECTED: " + String(error)) } process.on('unhandledRejection', callback)
twittear Resumen
Como cualquier otro lenguaje de programación, los errores son bastante frecuentes y naturales en JavaScript. En algunos casos, es posible que incluso deba arrojar errores intencionalmente para indicar la respuesta correcta a sus usuarios. Por lo tanto, comprender su anatomía y tipos es muy importante.
Además, debe estar equipado con las herramientas y técnicas adecuadas para identificar y evitar que los errores eliminen su aplicación.
En la mayoría de los casos, una estrategia sólida para manejar los errores con una ejecución cuidadosa es suficiente para todos los tipos de aplicaciones de JavaScript.
¿Hay algún otro error de JavaScript que aún no hayas podido resolver? ¿Alguna técnica para manejar los errores JS de manera constructiva? ¡Háganos saber en los comentarios a continuación!