¿Qué es un error en la programación?

Las cosas no siempre van bien en nuestros programas.

en particular, hay situaciones en las que podemos querer detener el programa o informar al Usuario si algo malo sucede.

por ejemplo:

  • El programa intentó abrir un archivo inexistente.
  • La conexión de red está rota.
  • El Usuario ha introducido una entrada no válida.,

en todos estos casos nosotros como programadores, creamos errores, o dejamos que el motor de programación cree algunos para nosotros.

después de crear el error podemos informar al usuario con un mensaje, o podemos detener la ejecución por completo.

¿qué es un error en JavaScript?

un error en JavaScript es un objeto, que luego se lanza para detener el programa.

para crear un nuevo error en JavaScript llamamos a la función constructora apropiada., Por ejemplo, para crear un nuevo error genérico que podemos hacer:

const err = new Error("Something bad happened!");

Cuando se crea un objeto de error también es posible omitir la etiqueta new palabra clave:

const err = Error("Something bad happened!");

una Vez creado, el objeto de error presenta tres propiedades:

  • message: una cadena con el mensaje de error.
  • name: el tipo de error.
  • stack : un seguimiento de pila de ejecución de funciones.,

por ejemplo, si creamos un nuevo objeto TypeError con el mensaje apropiado, el message llevará la cadena de error real, mientras que name será "TypeError":

Firefox también implementa un montón en Propiedades no estándar como columnNumber, filename, y lineNumber.,

Many types of errors in JavaScript

There are many types of errors in JavaScript, namely:

  • Error
  • EvalError
  • InternalError
  • RangeError
  • ReferenceError
  • SyntaxError
  • TypeError
  • URIError

Remember, all these error types are actual constructor functions meant to return a new error object.,

en su código utilizará principalmente Error y TypeError, dos de los tipos más comunes, para crear su propio objeto de error.

La mayoría de las veces, la mayoría de los errores vendrán directamente del motor JavaScript, como InternalError o SyntaxError.,

va x = '33';// SyntaxError: Unexpected identifier

O al uso de palabras clave reservadas en lugares equivocados, como await fuera de un async función:

function wrong(){ await 99;}wrong();// SyntaxError: await is only valid in async function

Otro ejemplo de TypeError se produce cuando se seleccione inexistente elementos HTML de la página:

Uncaught TypeError: button is null

además De estos tradicionales objetos de error, un AggregateError objeto se va a la tierra poco de JavaScript., AggregateError es conveniente para empaquetar varios errores juntos, como veremos más adelante.

además de estos errores incorporados, en el navegador también podemos encontrar:

  • DOMException.
  • DOMError, obsoleto y ya no se usa hoy.

DOMException es una familia de errores relacionados con las API Web., Se produce cuando hacemos cosas tontas en el navegador, como:

document.body.appendChild(document.cloneNode(true));

El resultado:

Uncaught DOMException: Node.appendChild: May not add a Document as a child

Para una lista completa, vea esta página en MDN.

¿Qué es una excepción?

La mayoría de los desarrolladores piensan que el error y las excepciones son la misma cosa. En realidad, un objeto de error se convierte en una excepción solo cuando se lanza.,

Para lanzar una excepción en JavaScript podemos usar throw, seguido por el objeto de error:

const wrongType = TypeError("Wrong type given, expected number");throw wrongType;

La forma corta es más común, en la mayoría de las bases de código que encontrarás:

throw TypeError("Wrong type given, expected number");

o

throw new TypeError("Wrong type given, expected number");

Es raro para lanzar excepciones fuera de una función o un bloque condicional. En su lugar, considere el siguiente ejemplo:

aquí comprobamos si el argumento de la función es una cadena., Si no es así, hacemos una excepción.

Técnicamente, puede tirar nada en JavaScript, no sólo objetos de error:

throw Symbol();throw 33;throw "Error!";throw null;

sin Embargo, es mejor evitar estas cosas: siempre tiro de error apropiado de los objetos, no primitivas.

al hacerlo, mantiene el manejo de errores consistente a través del código base. Otros miembros del equipo siempre pueden esperar acceder a error.messageo error.stack en el objeto error.

¿qué sucede cuando lanzamos una excepción?,

Las excepciones son como un ascensor que sube: una vez que lanzas uno, burbujea en la pila del programa, a menos que esté atrapado en algún lugar.

considere el siguiente código:

si ejecuta este código en un navegador o en un nodo.js, el programa se detiene e informa del error:

Además, puede ver la línea exacta donde ocurrió el error.

Este informe es un seguimiento de pila, y es útil para rastrear problemas en su código.

el seguimiento de la pila va de abajo hacia arriba., Así que aquí:

 toUppercase http://localhost:5000/index.js:3 <anonymous> http://localhost:5000/index.js:9

podemos decir:

  • algo en el programa en la línea 9 llamado toUppercase
  • toUppercase explotó en la línea 3

además de ver este seguimiento de pila en la consola del navegador, puede acceder a él en la propiedad stack del objeto error.

si la excepción no es capturada, es decir, el programador no hace nada para atraparla, el programa se bloqueará.,

Cuándo y dónde se detecta una excepción en el código depende del caso de uso específico.

por ejemplo, es posible que desee propagar una excepción en la pila para bloquear el programa por completo. Esto podría suceder para errores fatales, cuando es más seguro detener el programa en lugar de trabajar con datos no válidos.

habiendo introducido los conceptos básicos, ahora centraremos nuestra atención en el manejo de errores y excepciones tanto en código JavaScript síncrono como asíncrono.

manejo de errores síncronos

el código síncrono es la mayoría de las veces sencillo, por lo que su manejo de errores.,

El manejo de errores para funciones regulares

el código síncrono se ejecuta en el mismo orden en el que se escribe. Tomemos de nuevo el ejemplo anterior:

Aquí el motor llama y ejecuta toUppercase. Todo sucede sincrónicamente. Para capturar una excepción originados por dicha función sincrónica podemos usar try/catch/finally:

try { toUppercase(4);} catch (error) { console.error(error.message); // or log remotely} finally { // clean up}

Generalmente, try ofertas con el feliz camino, o con la llamada a la función que podría iniciar.,

catch en su lugar, captura la excepción real. Recibe el objeto de error, que podemos inspeccionar (y enviar de forma remota a algún registrador en producción).

la instrucción finally por otro lado se ejecuta independientemente del resultado de la función: ya sea que falle o tenga éxito, cualquier código dentro de finally se ejecutará.

recuerde:try/catch/finally es una construcción síncrona: ahora tiene forma de capturar excepciones provenientes de código asíncrono.,

manejo de errores para funciones de generador

una función de generador en JavaScript es un tipo especial de función.

se puede pausar y reanudar a voluntad, aparte de proporcionar un canal de comunicación bidireccional entre su ámbito interno y el consumidor.,

Para crear un generador de función, podemos poner una estrella * después de function palabra clave:

function* generate() {//}

una Vez dentro de la función, podemos usar yield a los valores de retorno:

function* generate() { yield 33; yield 99;}

El valor de retorno de un generador de función es un objeto iterador. Para extraer valores de un generador podemos usar dos enfoques:

  • llamando a next() en el objeto iterador.,
  • iteración con for...of.

Si tomamos nuestro ejemplo, para obtener valores del generador podemos hacer:

function* generate() { yield 33; yield 99;}const go = generate();

Aquí go se convierte en nuestro objeto iterador cuando llamamos función de generador.

a partir de ahora podemos llamar a go.next() para avanzar en la ejecución:

function* generate() { yield 33; yield 99;}const go = generate();const firstStep = go.next().value; // 33const secondStep = go.next().value; // 99

Los generadores también funcionan al revés: pueden aceptar valores y excepciones de la persona que llama.,

además next(), iterator objetos devueltos de los generadores tienen un throw() método.

con este método podemos detener el programa inyectando una excepción en el generador:

para atrapar dicho error, debe envolver su código dentro del generador con try/catch (y finally si es necesario):

function* generate() { try { yield 33; yield 99; } catch (error) { console.error(error.message); }}

las funciones del generador también pueden lanzar excepciones al exterior., El mecanismo para capturar estas excepciones es el mismo para capturar excepciones síncronas: try/catch/finally.

Aquí hay un ejemplo de una función de generador consumida desde el exterior con for...of:

aquí iteramos el camino feliz dentro de un bloque try. Si ocurre alguna excepción, la detenemos con catch.

manejo de errores asíncronos

JavaScript es síncrono por naturaleza, siendo un lenguaje de un solo subproceso.,

los entornos Host, como los motores de navegadores, aumentan JavaScript con una serie de API Web para interactuar con sistemas externos y para lidiar con operaciones vinculadas a E / S.

ejemplos de asincronicidad en el navegador son timeouts, events, Promise.

el manejo de errores en el mundo asíncrono es distinto de su contraparte síncrona.

veamos algunos ejemplos.

manejo de errores para temporizadores

al comienzo de sus exploraciones con JavaScript, después de aprender sobre try/catch/finally, puede que tenga la tentación de ponerlo alrededor de cualquier bloque de código.,

Considere el siguiente fragmento de código:

function failAfterOneSecond() { setTimeout(() => { throw Error("Something went wrong!"); }, 1000);}

Esta función produce después de aproximadamente 1 segundo. ¿Cuál es la forma correcta de manejar esta excepción?

El siguiente ejemplo no funciona:

Como hemos dicho, try/catch es sincrónico. Por otro lado tenemos setTimeout, una API de navegador para temporizadores.

en el momento en que se ejecuta la devolución de llamada pasada a setTimeout, nuestro try/catch ya no existe. El programa se bloqueará porque no pudimos capturar la excepción.,

viajar por dos vías diferentes:

Track A: --> try/catchTrack B: --> setTimeout --> callback --> throw

Si no queremos bloquear el programa, para controlar el error correctamente debemos mover try/catch dentro de la devolución de llamada para setTimeout.

Pero, este enfoque no tiene mucho sentido la mayoría de las veces. Como veremos más adelante, el manejo de errores asincrónico con Promises proporciona una mejor ergonomía.,

manejo de errores para eventos

los nodos HTML en el modelo de objetos de documento están conectados a EventTarget, el ancestro común para cualquier emisor de eventos en el navegador.

eso significa que podemos escuchar eventos en cualquier elemento HTML de la página.

(Nodo.js apoyará EventTarget en una versión futura).

la mecánica de manejo de errores para eventos DOM sigue el mismo esquema de cualquier API Web asíncrona.

considere el siguiente ejemplo:

aquí lanzamos una excepción tan pronto como se hace clic en el botón. ¿Cómo lo atrapamos?, Este patrón no funciona y no evitará que el programa se bloquee:

como en el ejemplo anterior con setTimeout, cualquier devolución de llamada pasada a addEventListener se ejecuta de forma asíncrona:

Track A: --> try/catchTrack B: --> addEventListener --> callback --> throw

si no queremos bloquear el programa, para manejar el error correctamente debemos mover try/catch dentro de la devolución de llamada para addEventListener.

pero de nuevo, hay poco de valor en hacer esto.,

al igual que con setTimeout, la excepción lanzada por una ruta de código asincrónica no se puede capturar desde el exterior y bloqueará su programa.

en las siguientes secciones veremos cómo Promises y async/await pueden facilitar el manejo de errores para código asíncrono.

¿qué tal onerror?

los elementos HTML tienen varios controladores de eventos como onclick, onmouseenter, onchange por nombrar algunos.

también Hay onerror, pero no tiene nada que ver con el throw y amigos.,

el controlador de eventos onerror dispara cada vez que un elemento HTML como una etiqueta <img> o una etiqueta <script> golpea un recurso inexistente.,b4″>// omitted<body><img src="https://www.valentinog.com/blog/error/nowhere-to-be-found.png" alt="So empty!"></body>// omitted

al visitar un documento HTML con un recurso faltante o inexistente, la consola del navegador registra el error:

GET http://localhost:5000/https://www.valentinog.com/blog/error/nowhere-to-be-found.png

en nuestro JavaScript tenemos la oportunidad de «atrapar» este error con el controlador de eventos apropiado:

const image = document.querySelector("img");image.onerror = function(event) { console.log(event);};

o mejor:

const image = document.querySelector("img");image.addEventListener("error", function(event) { console.log(event);});

Este patrón es útil para cargar recursos alternativos en lugar de imágenes o scripts faltantes.,

Pero recuerde: onerror, no tiene nada que ver con la etiqueta throw o try/catch.

manejo de errores con Promise

para ilustrar el manejo de errores con Promise, «promisificaremos» uno de nuestros ejemplos originales. Modificamos la siguiente función:

en lugar de devolver una cadena simple, o una excepción, usamos respectivamente Promise.reject y Promise.resolve para manejar el error y el éxito:

(técnicamente no hay nada asincrónico en este código, pero sirve para ilustrar el punto).,

Ahora que la función es «promisified» podemos adjuntar then para consumir el resultado, y catch para el manejo de los rechazados de la Promesa:

toUppercase(99) .then(result => result) .catch(error => console.error(error.message));

Este código de registro:

Wrong type given, expected a string

En el ámbito de la Promesa, catch es el constructo para el manejo de errores.,

además catch y then tenemos también finally, similar a la de finally en el try/catch.

como su «relativo» síncrono, Promise finally se ejecuta independientemente del resultado de Promise:

toUppercase(99) .then(result => result) .catch(error => console.error(error.message)) .finally(() => console.log("Run baby, run"));

siempre tenga en cuenta que cualquier devolución de llamada pasada a then/catch/finally es manejado asincrónicamente por la cola de microtask. Son tareas micro con prioridad sobre tareas macro como eventos y temporizadores.,

Promise, error, and throw

como una mejor práctica al rechazar una promesa, es conveniente proporcionar un objeto de error:

Promise.reject(TypeError("Wrong type given, expected a string"));

al hacerlo, mantiene el manejo de errores consistente a través de la base de código. Otros miembros del equipo siempre pueden esperar acceder a error.message, y lo más importante es que puede inspeccionar los rastros de la pila.

además de Promise.reject, podemos salir de una cadena de promesas lanzando una excepción.,

Considere el siguiente ejemplo:

Promise.resolve("A string").then(value => { if (typeof value === "string") { throw TypeError("Expected a number!"); }});

Podemos resolver una Promesa con una cadena y, a continuación, la cadena se rompe de forma inmediata con la etiqueta throw.

para detener la propagación de excepciones utilizamos catch, como de costumbre:

Este patrón es común en fetch, donde comprobamos el objeto de respuesta en busca de errores:

Aquí la excepción puede ser interceptada con catch., Si fallamos, o decidimos no atraparlo allí, la excepción es libre de burbujear en la pila.

esto no es malo per se, pero los diferentes entornos reaccionan de manera diferente a los rechazos no capturados.nodo

.js, por ejemplo, en el futuro le permitirá accidente de cualquier programa donde la Promesa de que ellos son de la onu de mango:

DeprecationWarning: Unhandled promise rejections are deprecated. In the future, promise rejections that are not handled will terminate the Node.js process with a non-zero exit code.

Mejores capturas!

manejo de errores para temporizadores «prometidos»

con temporizadores o eventos no es posible capturar excepciones lanzadas desde una devolución de llamada., Vimos un ejemplo en la sección anterior:

una solución ofrecida por Promise consiste en la» promisificación » de nuestro código. Básicamente, nos envuelven a nuestro temporizador con una Promesa:

function failAfterOneSecond() { return new Promise((_, reject) => { setTimeout(() => { reject(Error("Something went wrong!")); }, 1000); });}

Con la etiqueta reject partimos de una Promesa de rechazo, lo que lleva a un error de objeto.,

en este punto podemos manejar la excepción con catch:

failAfterOneSecond().catch(reason => console.error(reason.message));

Nota: Es común usar value como el valor devuelto de una promesa, y reason como el objeto devuelto de un rechazo.nodo

.js tiene una utilidad llamada promisify para facilitar la» promisificación » de las API de devolución de llamada de estilo antiguo.

manejo de errores en Promise.,all

El Método estático Promise.all acepta una matriz de Promise, y devuelve una matriz de resultados de todas las Promise resolutivas:

si alguna de estas Promise rechaza, Promise.all rechaza con el error de la primera promesa rechazada.

para manejar estas situaciones en Promise.all usamos catch, como hicimos en la sección anterior:

para ejecutar una función independientemente del resultado de Promise.all, nuevamente, podemos usar finally:

manejo de errores en promise.,cualquier

podemos considerar Promise.any (Firefox > 79, Chrome > 85) como el opuesto de Promise.all.

mientras que Promise.all devuelve un error incluso si una sola promesa en la matriz rechaza, Promise.any nos da siempre la primera promesa resuelta (si está presente en la matriz) independientemente de que se haya producido cualquier rechazo.

en caso de que toda la promesa pase a Promise.any reject, el error resultante es un AggregateError., Considere el siguiente ejemplo:

aquí manejamos el error con catch., El resultado de este código es:

AggregateError: No Promise in Promise.any was resolvedAlways runs!

El AggregateError objeto tiene las mismas propiedades básicas del Error, además de un errors propiedad:

// .catch(error => console.error(error.errors))//

Esta propiedad es una matriz de cada individuo error producido por el rechazo:

el manejo de Errores en la Promesa.,race

El Método estático Promise.race acepta una matriz de Promise:

el resultado es la primera promesa que gana la»race».

¿Qué hay de los rechazos entonces? Si la promesa de rechazo no es la primera en aparecer en la matriz de entrada, Promise.race resuelve:

Si el rechazo en su lugar aparece como el primer elemento de la matriz, Promise.race rechaza, y debemos atrapar el rechazo:

manejo de errores en Promise.allSettled

Promise.allSettled es una adición de ECMAScript 2020 al lenguaje.,

no Hay mucho para manejar con este método estático ya que el resultado siempre será resuelto Promesa, incluso si uno o más de entrada Promesa rechaza.

considere el siguiente ejemplo:

pasamos aPromise.allSettled un array que consta de dos Promise: uno resuelto y otro rechazado.

en este caso catch nunca será golpeado. finally en su lugar se ejecuta.,

el resultado de este código, registrado then es:

manejo de errores para async/await

async/await en JavaScript denota funciones asíncronas, pero desde el punto de vista del lector se benefician de toda la legibilidad de las funciones síncronas.,

para mantener las cosas simples tomaremos nuestra función síncrona anterior toUppercase, y la transformaremos en una función asíncrona poniendo async antes de la palabra clave function:

simplemente prefijando una función con async hacemos que la función devuelva una promesa., Eso significa que podemos encadenar then, catch, y finally después de la llamada a la función:

cuando lanzamos desde una función async la excepción se convierte en causa de rechazo para la promesa subyacente.

cualquier error puede ser interceptado con catch desde el exterior.

lo Más importante, además de este estilo podemos usar try/catch/finally, tanto como lo haría con una función sincrónica.,

en el siguiente ejemplo llamamos a toUppercase desde otra función, consumer, que convenientemente envuelve la llamada a la función con try/catch/finally:

la salida es:

Wrong type given, expected a stringAlways runs!

sobre el mismo tema: ¿cómo lanzar errores de funciones asincrónicas en JavaScript?

manejo de errores para generadores asíncronos

Los generadores asíncronos en JavaScript son funciones de generador capaces de generar promesas en lugar de valores simples.,

combinan las funciones del generador con async. El resultado es una función generadora cuyos objetos iteradores exponen una promesa al consumidor.

para crear un generador asíncrono declaramos una función de generador con la estrella *, prefijada con async:

async function* asyncGenerator() { yield 33; yield 99; throw Error("Something went wrong!"); // Promise.reject}

al estar basado en promise, las mismas reglas para el manejo de errores se aplican aquí., throw dentro de un generador asíncrono causa un rechazo de promesa, que interceptamos con catch.

para extraer promesas de generadores asíncronos podemos usar dos enfoques:

  • then handlers.
  • iteración asíncrona.

del ejemplo anterior sabemos con seguridad que habrá una excepción después de los dos primeros yield., Esto significa que podemos hacer:

El resultado de este código es:

{ value: 33, done: false }{ value: 99, done: false }Something went wrong!

El otro método utiliza async iteración con la etiqueta for await...of. Para usar la iteración asincrónica necesitamos envolver al consumidor con una función async.,

Aquí está el ejemplo completo:

y como con async/await manejamos cualquier excepción potencial con try/catch:

la salida de este código es:

3399Something went wrong!

el objeto iterador devuelto desde una función de generador asíncrono también tiene un método throw(), al igual que su contraparte síncrona.,

llamar a throw() en el objeto iterador aquí no lanzará una excepción, sino un rechazo de promesa:

para manejar esta situación desde el exterior podemos hacer:

go.throw(Error("Let's reject!")).catch(reason => console.error(reason.message));

pero no olvidemos que los objetos iteradores throw() envían la excepción dentro del generador. Esto significa que también podemos aplicar el siguiente patrón:

manejo de errores en el nodo.JS

manejo de errores síncronos en el nodo.JS

manejo de errores síncronos en el nodo.,js no difiere demasiado de lo que vimos hasta ahora.

para código síncrono, try/catch/finally funciona bien.

sin embargo, las cosas se ponen interesantes si echamos un vistazo al mundo asíncrono.

manejo de errores asíncronos en el nodo.js: el patrón de devolución de llamada

Para código asíncrono, nodo.js se basa fuertemente en dos modismos:

  • El patrón de devolución de llamada.
  • emisores de eventos.

en el patrón de devolución de llamada, nodo asíncrono.las API de js aceptan una función que se maneja a través del bucle de eventos y se ejecuta tan pronto como la pila de llamadas está vacía.,

considere el siguiente código:

Si extraemos la devolución de llamada de este listado, podemos ver cómo se supone que debe tratar con los errores:

//function(error, data) { if (error) console.error(error); // do stuff with the data }//

Si surge algún error al leer la ruta dada con fs.readFile, obtenemos un objeto de error.

en este punto podemos:

  • simplemente registrar el objeto de error como lo hicimos.
  • lanzar una excepción.
  • pase el error a otra devolución de llamada.,

para lanzar una excepción podemos hacer:

sin embargo, al igual que con los eventos y temporizadores en el DOM, esta excepción bloqueará el programa. El siguiente intento de detenerlo con try/catch no funcionará:

pasar el error a otra devolución de llamada es la opción preferida, si no queremos bloquear el programa:

Aquí errorHandler es lo que sugiere el nombre, una función simple para el manejo de errores:

manejo de errores asíncronos en el nodo.JS: emisores de eventos

gran parte de lo que haces en Node.js se basa en eventos., La mayoría de las veces interactúas con un objeto emisor y algunos observadores escuchando mensajes.

cualquier módulo impulsado por eventos (como net, por ejemplo) en el nodo.js extiende una clase raíz llamada EventEmitter.

EventEmitter en el Nodo.js tiene dos métodos fundamentales: on y emit.

considere este simple Servidor HTTP:

aquí escuchamos dos eventos: escucha y conexión.

además de estos eventos, los emisores de eventos también exponen un evento de error, disparado en caso de errores.,

Si se ejecuta este código escuchando en el puerto 80 en lugar de la del ejemplo anterior, se obtendrá una excepción:

Resultado:

Para atrapar podemos registrar un controlador de eventos para el error:

server.on("error", function(error) { console.error(error.message);});

Esto de impresión:

listen EACCES: permission denied 127.0.0.1:80

además, el programa no se cuelgue.

para obtener más información sobre el tema, considere también leer «manejo de errores en el nodo.js».,

terminando

en esta guía cubrimos el manejo de errores en JavaScript para todo el espectro, desde código síncrono simple hasta primitivas asíncronas avanzadas.

Hay muchas maneras en que una excepción puede manifestarse en nuestros programas JavaScript.

Las excepciones del código síncrono son las más sencillas de detectar. Las excepciones a las rutas de código asíncronas pueden ser difíciles de tratar.

mientras tanto, las nuevas API de JavaScript en el navegador casi todas se dirigen hacia Promise., Este patrón generalizado facilita el manejo de excepciones con then/catch/finally, o con try/catchpara async/await.

después de leer esta guía, debe ser capaz de reconocer todas las diferentes situaciones que pueden surgir en sus programas y detectar sus excepciones correctamente.

Gracias por leer y estad atentos!

Este post también está disponible en:

  • Japonés
  • China