no importa lo buenos que seamos en la programación, a veces nuestros scripts tienen errores. Pueden ocurrir debido a nuestros errores, una entrada inesperada del usuario, una respuesta errónea del servidor y por mil otras razones.
generalmente, un script «muere» (se detiene inmediatamente) en caso de un error, imprimiéndolo en la consola.
pero hay una construcción de sintaxis try..catch
que nos permite «atrapar» errores para que el script pueda, en lugar de morir, hacer algo más razonable.,
El «try…catch» sintaxis
El try..catch
construcción de dos bloques principales: try
y luego catch
:
try { // code...} catch (err) { // error handling}
esto funciona así:
- en Primer lugar, el código en el
try {...}
se ejecuta. - Si no hubo errores, entonces
catch(err)
es ignorado: la ejecución alcanza el final detry
y se va, saltarcatch
., - si se produce un error, la ejecución
try
se detiene y el control fluye al principio decatch(err)
. La variableerr
(podemos usar cualquier nombre para ella) contendrá un objeto de error con detalles sobre lo que sucedió.
Así, un error dentro de la etiqueta try {…}
bloque de no matar a la secuencia de comandos – tenemos una oportunidad de manejarlo en el catch
.,
veamos algunos ejemplos.
try..catch
solo funciona para los errores de tiempo de ejecuciónPara try..catch
para el trabajo, el código debe ser ejecutable. En otras palabras, debería ser JavaScript válido.
no funciona si el código es sintácticamente incorrecta, por ejemplo, se ha inigualable llaves:
try { {{{{{{{{{{{{} catch(e) { alert("The engine can't understand this code, it's invalid");}
El motor de JavaScript primero lee el código, y luego lo ejecuta., Los errores que ocurren en la fase de lectura se llaman errores de «tiempo de análisis» y son irrecuperables (desde el interior de ese código). Eso es porque el motor no puede entender el código.
entonces,try..catch
solo puede manejar errores que ocurren en código válido. Estos errores se denominan » errores de tiempo de ejecución «o, a veces,»excepciones».
objeto de Error
Cuando se produce un error, JavaScript genera un objeto que contiene los detalles sobre él., El objeto que se pasa como argumento a catch
:
try { // ...} catch(err) { // <-- the "error object", could use another word instead of err // ...}
Para todos los integrados en los errores, el objeto de error tiene dos propiedades principales:
name
Error de nombre. Por ejemplo, para una variable indefinida que es"ReferenceError"
.message
mensaje Textual sobre los detalles del error.
Hay otras propiedades no estándar disponibles en la mayoría de los entornos., Una de las más utilizadas y soportadas es:
stack
pila de llamadas actuales: una cadena con información sobre la secuencia de llamadas anidadas que llevaron al error. Se utiliza para fines de depuración.
Por ejemplo:
enlace opcional «catch»
Si no tenemos detalles del error, catch
puede omitirlo:
try { // ...} catch { // <-- without (err) // ...}
el Uso de «try…catch»
Vamos a explorar una de la vida real de casos de uso de try..catch
.
como ya sabemos, JavaScript soporta el JSON.método parse (str) para leer valores codificados por JSON.
Por lo general se utiliza para decodificar los datos recibidos a través de la red, desde el servidor u otra fuente.,
lo recibimos y llamamos a JSON.parse
así:
Puede encontrar información más detallada sobre JSON en el capítulo métodos JSON, toJSON.
Sijson
está mal formado, JSON.parse
genera un error, por lo que el script»muere».
¿deberíamos estar satisfechos con eso? ¡Claro que no!
de esta manera, si algo está mal con los datos, el visitante nunca lo sabrá (a menos que abra la consola del desarrollador). Y a la gente realmente no le gusta cuando algo «simplemente muere» sin ningún mensaje de error.,
usemos try..catch
para manejar el error:
Aquí usamos el bloque catch
solo para mostrar el mensaje, pero podemos hacer mucho más: enviar una nueva solicitud de red, Sugerir una alternativa al visitante, enviar información sobre el error a una instalación de registro,.. Todo mucho mejor que morir.
lanzar nuestros propios errores
¿Qué pasa si json
es sintácticamente correcto, pero no tiene una propiedad name
?,
let json = '{ "age": 30 }'; // incomplete datatry { let user = JSON.parse(json); // <-- no errors alert( user.name ); // no name!} catch (e) { alert( "doesn't execute" );}
Aquí JSON.parse
se ejecuta con normalidad, pero la ausencia de name
es en realidad un error para nosotros.
para unificar el manejo de errores, usaremos el operador throw
.
operador»Throw»
el operador throw
genera un error.
La sintaxis es:
throw <error object>
Técnicamente, se puede usar cualquier cosa como un objeto de error., Esto puede ser incluso primitivo, como un número o una cadena, pero es mejor usar objetos, preferiblemente con propiedades name
y message
(para permanecer algo compatible con errores incorporados).
JavaScript tiene muchos construidos en los constructores de los errores estándar: Error
, SyntaxError
, ReferenceError
, TypeError
y otros. También podemos usarlos para crear objetos de error.,
Su sintaxis es:
let error = new Error(message);// orlet error = new SyntaxError(message);let error = new ReferenceError(message);// ...
Para los errores integrados (no para todos los objetos, de los errores), el name
la propiedad es exactamente el nombre del constructor. Y message
se toma del argumento.,
Por ejemplo:
let error = new Error("Things happen o_O");alert(error.name); // Erroralert(error.message); // Things happen o_O
Vamos a ver qué tipo de error JSON.parse
genera:
try { JSON.parse("{ bad json o_O }");} catch(e) { alert(e.name); // SyntaxError alert(e.message); // Unexpected token b in JSON at position 2}
Como podemos ver, que el SyntaxError
.
Y en nuestro caso, la ausencia de name
es el error, ya que los usuarios deben tener un name
.,
así que vamos a lanzarlo:
en la línea(*)
, el operadorthrow
genera unSyntaxError
con elmessage
, de la misma manera que JavaScript lo generaría él mismo . La ejecución de try
se detiene inmediatamente y el flujo de control salta a catch
.
Ahora catch
se convirtió en un solo lugar para todo el manejo de errores: tanto para JSON.parse
y otros casos.,
Regeneración de
En el ejemplo anterior, podemos usar try..catch
para manejar datos incorrectos. Pero, ¿es posible que se produzca otro error inesperado dentro del bloque try {...}
? Como un error de programación (la variable no está definida) o algo más, no solo esta cosa de «datos incorrectos».
Por ejemplo:
por supuesto, todo es posible! Los programadores cometen errores. Incluso en las utilidades de código abierto utilizadas por millones durante décadas, de repente se puede descubrir un error que conduce a terribles hacks.,
en nuestro caso, try..catch
se coloca para detectar errores de «datos incorrectos». Pero por su naturaleza, catch
obtiene todos los errores de try
. Aquí se obtiene un error inesperado, pero todavía muestra el mismo mensaje "JSON Error"
. Eso está mal y también hace que el código sea más difícil de depurar.
para evitar tales problemas, podemos emplear la técnica de «repensar». La regla es simple:
Catch solo debe procesar los errores que conoce y «repensar» todos los demás.,
la técnica de «repensar» se puede explicar con más detalle como:
- Catch obtiene todos los errores.
- En el bloque
catch(err) {...}
analizamos el objeto de errorerr
. - si no sabemos cómo manejarlo, lo hacemos
throw err
.
Generalmente, podemos verificar el tipo de error usando el operador instanceof
:
También podemos obtener el nombre de la clase de error de la propiedad err.name
. Todos los errores nativos lo tienen. Otra opción es leer err.constructor.name
.,
En el código a continuación, utilizamos la regeneración de modo que catch
maneja SyntaxError
:
El error de lanzar en línea (*)
dentro de catch
bloque «cae» de try..catch
y puede ser capturado por una capa exterior de try..catch
construir (si es que existe), o mata a la secuencia de comandos.
así que el bloquecatch
en realidad solo maneja los errores que sabe cómo tratar y «omite» todos los demás.,
El siguiente ejemplo muestra cómo dichos errores pueden ser capturados por un mayor nivel de try..catch
:
Aquí readData
sólo sabe cómo manejar SyntaxError
, mientras que el exterior try..catch
sabe cómo manejar todo.
try…catch…finally
Espere, eso no es todo.
la construcción try..catch
puede tener una cláusula de código más: finally
.,
Si es que existe, se ejecuta en todos los casos:
- después de
try
, si no hubo errores, - después de
catch
, si hubo errores.
La sintaxis extendida se parece a esto:
try { ... try to execute the code ...} catch(e) { ... handle errors ...} finally { ... execute always ...}
Trate de ejecutar este código:
try { alert( 'try' ); if (confirm('Make an error?')) BAD_CODE();} catch (e) { alert( 'catch' );} finally { alert( 'finally' );}
El código tiene dos modos de ejecución:
- Si usted contesta «Sí» a «Hacer un error?»entonces
try -> catch -> finally
., - Si dices «No», entonces
try -> finally
.
la cláusula finally
se usa a menudo cuando comenzamos a hacer algo y queremos finalizarlo en cualquier caso de resultado.
por ejemplo, queremos medir el tiempo que tarda una función Fibonacci numbers fib(n)
. Naturalmente, podemos empezar a medir antes de que se ejecute y terminar después. Pero, ¿qué pasa si hay un error durante la llamada a la función? En particular, la implementación de fib(n)
en el siguiente código devuelve un error para números negativos o no enteros.,
la cláusula finally
es un gran lugar para terminar las mediciones sin importar qué.
Aquí finally
garantiza que el tiempo se mide correctamente en ambas situaciones – en el caso de una ejecución exitosa de fib
y en caso de un error en ella:
Usted puede comprobar ejecutando el código con la introducción de 35
dentro de prompt
se ejecuta normalmente, finally
después de try
., Y luego ingrese -1
div – – habrá un error inmediato, y la ejecución tomará 0ms
. Ambas mediciones se realizan correctamente.
En otras palabras, la función puede terminar con return
o throw
, que no importa. La cláusula finally
se ejecuta en ambos casos.,
try..catch..finally
por Favor, tenga en cuenta que result
y diff
variables en el código anterior se declaran antes de try..catch
.
de lo contrario, si declaramos let
en el bloque try
, solo sería visible dentro de él.
try..finally
El try..finally
construir, sin catch
cláusula, también es útil., Lo aplicamos cuando no queremos manejar errores aquí (dejarlos caer), pero queremos asegurarnos de que los procesos que iniciamos estén finalizados.
function func() { // start doing something that needs completion (like measurements) try { // ... } finally { // complete that thing even if all dies }}
En el código anterior, un error dentro de try
siempre se cae, porque no hay ninguna catch
. Pero finally
funciona antes de que el flujo de ejecución salga de la función.
global catch
la información de esta sección no forma parte del núcleo de JavaScript.,
imaginemos que tenemos un error fatal fuera de try..catch
, y el script murió. Como un error de programación o alguna otra cosa terrible.
¿Hay alguna manera de reaccionar ante tales ocurrencias? Es posible que queramos registrar el error, mostrar algo al usuario (normalmente no ven mensajes de error), etc.
no hay ninguno en la especificación, pero los entornos generalmente lo proporcionan, porque es realmente útil. Por ejemplo, Node.js tiene process.on("uncaughtException")
para eso. Y en el navegador podemos asignar una función a la ventana especial.,propiedad onerror, que se ejecutará en caso de un error no capturado.
La sintaxis:
window.onerror = function(message, url, line, col, error) { // ...};
message
mensaje de Error. url
URL del script donde ocurrió el error. line
, col
números de Línea y columna donde el error ocurrió. error
objeto de Error.,
por ejemplo:
el rol del controlador global window.onerror
generalmente no es recuperar la ejecución del script, probablemente sea imposible en caso de errores de programación, sino enviar el mensaje de error a los desarrolladores.
funcionan así:
- Nos registramos en el servicio y obtenemos un trozo de JS (o una URL de script) de ellos para insertar en las páginas.
- ese script JS establece una función personalizada
window.onerror
. - cuando se produce un error, envía una solicitud de red al servicio.
- podemos iniciar sesión en la interfaz web del servicio y ver los errores.,
Summary
la construcción try..catch
permite manejar errores de tiempo de ejecución. Literalmente permite» intentar «ejecutar el código y» atrapar » los errores que pueden ocurrir en él.
la sintaxis es:
puede no haber catch
section o no finally
, por lo que las construcciones más cortas try..catch
y try..finally
también son válidas.
los objetos de Error tienen las siguientes propiedades:
-
message
– el mensaje de error legible por humanos., -
name
div – – la cadena con el nombre de error (nombre del constructor de error). -
stack
(no estándar, pero bien soportado) – la pila en el momento de la creación del error.
si no se necesita un objeto de error, podemos omitirlo usando catch {
en lugar de catch(err) {
.
También podemos generar nuestros propios errores utilizando el operador throw
., Técnicamente, el argumento de throw
puede ser cualquier cosa, pero generalmente es un objeto de error heredado de la clase incorporada Error
. Más sobre la extensión de errores en el próximo capítulo.
repensar es un patrón muy importante de manejo de errores: un bloquecatch
generalmente espera y sabe cómo manejar el tipo de error en particular, por lo que debe repensar errores que no sabe.
incluso si no tenemos try..catch
, la mayoría de los entornos nos permiten configurar un controlador de errores «global» para detectar errores que «caen»., En el navegador, eso es window.onerror
.