Todos los ingenieros front-end saben que JavaScript tiene capacidades básicas de manejo de excepciones. Podemos lanzar un nuevo error (), y el navegador también lanzará una excepción cuando llamemos el error de la API. Pero se estima que la mayoría de los ingenieros front-end nunca han considerado recopilar esta información de excepción
De todos modos, siempre que la actualización no se reproduzca después de un error de JavaScript, el usuario puede resolver el problema refrescante, y el navegador no se bloqueará, y estará bien si no ha sucedido. Esta suposición era cierta antes de que la aplicación de una sola página se hiciera popular. La aplicación actual de una sola página es extremadamente compleja después de ejecutarse por un período de tiempo. Los usuarios pueden haber realizado varias operaciones de entrada antes de venir aquí. ¿Cómo pueden refrescar si dicen que quieren? ¿No volvería a trabajar por completo las operaciones anteriores? Por lo tanto, todavía es necesario que captemos y analicemos esta información de excepción, y luego podemos modificar el código para evitar afectar la experiencia del usuario.
Cómo atrapar excepciones
Nos escribimos, lanzamos un nuevo error (). Si queremos capturar, ciertamente podemos capturarlo porque sabemos muy bien dónde se escribe el tiro. Sin embargo, las excepciones que ocurren al llamar a la API del navegador no son necesariamente tan fáciles de atrapar. Algunas API dicen que se lanzarán excepciones al estándar, y algunas API solo tienen navegadores individuales que lanzan excepciones debido a diferencias o defectos de implementación. Para el primero también podemos atraparlo a través de Try-Catch, para el segundo debemos escuchar las excepciones globales y luego atraparlo.
captura de try
Si se sabe que algunas API del navegador arrojan excepciones, debemos poner la llamada en la captura de prueba para evitar que todo el programa ingrese a un estado ilegal debido a errores. Por ejemplo, Window.localStorage es una API así. Se lanzará una excepción después de que la escritura de datos exceda el límite de capacidad, y esto también será cierto en el modo de navegación privada de Safari.
La copia del código es la siguiente:
intentar {
localStorage.SetItem ('date', date.now ());
} capt (error) {
reporterRor (error);
}
Otro escenario de prueba de prueba común aplicable son las devoluciones de llamada. Debido a que el código de la función de devolución de llamada es incontrolable, no sabemos qué tan bueno es el código y si se llamarán a otras API que lanzan excepciones. Para no hacer que se ejecuten otros códigos después de llamar a la devolución de llamada debido a los errores de devolución de llamada, es necesario volver a poner la llamada en la captura de prueba.
La copia del código es la siguiente:
oyentes.ForEach (función (oyente) {
intentar {
oyente();
} capt (error) {
reporterRor (error);
}
});
ventana.
Para los lugares que la captura de prueba no puede cubrir, si se produce una excepción, solo se puede capturar a través de la ventana.
La copia del código es la siguiente:
Window.onerror =
function (errorMessage, scripturi, lino number) {
ReporterRor ({
Mensaje: ErrorMessage,
Script: Scripturi,
Línea: Linenumber
});
}
Tenga cuidado de no ser inteligente y usar ventana. Muchos navegadores solo implementan ventana. Animán, o solo la implementación de la ventana. Teniendo en cuenta que el borrador estándar también define ventana.
Propiedad que falta
Supongamos que tenemos una función ReporterRor para recopilar excepciones atrapadas y luego enviarlas en lotes a almacenamiento del lado del servidor para consulta y análisis, ¿qué información queremos recopilar? Más información útil incluye: Tipo de error (nombre), mensaje de error (mensaje), dirección de archivo de script (script), número de línea (línea), número de columna (columna) y traza de pila. Si se atrapa una excepción a través de Try-Catch, toda esta información está en el objeto de error (compatible con los navegadores convencionales), por lo que ReporterRor también puede recopilar esta información. Pero si se captura a través de la ventana. Animilla, todos sabemos que esta función del evento tiene solo 3 parámetros, por lo que se pierde la información inesperada de estos 3 parámetros.
Mensajes de serializar
Si el objeto de error es creado por nosotros mismos, entonces Error.message es controlado por nosotros. Básicamente, lo que ponemos en error. (El navegador realmente realizará modificaciones ligeramente, como agregar el 'error no capturado:' prefijo). Por lo tanto, podemos serializar los atributos que nos preocupa (como json.stringify) y almacenarlos en el error. Por supuesto, esto se limita al objeto de error que creamos nosotros mismos.
El quinto parámetro
Los fabricantes de navegadores también conocen las restricciones a las que las personas están sujetas cuando usan Window. y comienzan a agregar nuevos parámetros a la ventana. Teniendo en cuenta que solo los números de fila y ningún número de columna parecen ser muy simétricos, es decir, primero agregó los números de columna y los colocó en el cuarto parámetro. Sin embargo, lo que todos están más preocupados es si pueden obtener la pila completa, por lo que Firefox dijo que sería mejor poner la pila en el quinto parámetro. Pero Chrome dijo que sería mejor poner todo el objeto de error en el quinto parámetro. Cualquier atributo que desee leer, incluidos los atributos personalizados. Como resultado, debido a que Chrome es más rápido, se implementó una nueva ventana. Se implementó la firma de Anderror en Chrome 30, lo que resultó en la siguiente escritura del borrador estándar.
La copia del código es la siguiente:
Window.oNerror = function (
Errormessage,
SIRTURI,
Lino,
columnnumber,
error
) {
if (error) {
reporterRor (error);
} demás {
ReporterRor ({
Mensaje: ErrorMessage,
Script: Scripturi,
Línea: Linenumber,
Columna: Number de columna
});
}
}
Regularidad de los atributos
Los nombres de las propiedades del objeto de error que discutimos anteriormente se basan en métodos de nomenclatura de Chrome. Sin embargo, diferentes navegadores nombran las propiedades del objeto de error de manera diferente. Por ejemplo, la dirección del archivo de script se llama script en Chrome pero el nombre de archivo en Firefox. Por lo tanto, también necesitamos una función especial para normalizar el objeto de error, es decir, para asignar diferentes nombres de atributos a un nombre de atributo unificado. Para prácticas específicas, consulte este artículo. Aunque la implementación del navegador se actualizará, no será demasiado difícil para nadie mantener dicha tabla de mapeo.
Similar es el formato de rastreo de pila. Esta propiedad guarda la información de la pila de una excepción cuando ocurre en texto plano. Dado que los formatos de texto utilizados por cada navegador son diferentes, también es necesario mantener una expresión regular para extraer el nombre de la función (identificador), el archivo (script), el número de línea (línea) y el número de columna (columna) de cada cuadro del texto plano.
Limitaciones de seguridad
Si también ha encontrado un error con el mensaje 'Error de script'. Comprenderá de lo que estoy hablando, que en realidad son las limitaciones del navegador para los archivos de script de diferentes fuentes. La razón de esta restricción de seguridad es la siguiente: supongamos que el HTML devuelto por un banquero en línea después de iniciar sesión es diferente del HTML visto por un usuario anónimo, un sitio web de terceros puede poner el URI de este banco en línea en el atributo Script.src. Por supuesto, HTML no puede analizarse como JS, por lo que el navegador organizará una excepción, y este sitio web de terceros puede determinar si el usuario ha iniciado sesión analizando la ubicación de la excepción. Por esta razón, el navegador filtra todas las excepciones lanzadas por diferentes archivos de script de origen, dejando solo un mensaje sin cambios como 'error de script'. Y todos los demás atributos desaparecen.
Para los sitios web de una determinada escala, es normal que los archivos de script se coloquen en CDN y se colocan diferentes fuentes. Ahora, incluso si crea un pequeño sitio web usted mismo, los marcos comunes como JQuery y Backbone pueden hacer referencia directamente a la versión en el CDN público para acelerar las descargas de usuarios. Por lo tanto, esta restricción de seguridad causa algunos problemas, lo que hace que la información de excepción que recopilamos de Chrome y Firefox sea inútil 'error de script'.
CORS
Si desea evitar esta restricción, solo asegúrese de que el archivo de script y la página en sí sean del mismo origen. Pero, ¿no colocar los archivos de script en servidores que CDN no aceleran para ralentizar la velocidad de descarga del usuario? Una solución es continuar colocando el archivo de script en el CDN, usar XMLHTTPRequest para descargar el contenido a través de CORS y luego crear una etiqueta <Script> para inyectarlo en la página. El código integrado en la página es, por supuesto, el mismo origen.
Esto es fácil de decir, pero hay muchos detalles para implementar. Para dar un ejemplo simple:
La copia del código es la siguiente:
<script src = "http://cdn.com/step1.js"> </script>
<script>
(función step2 () {}) ();
</script>
<script src = "http://cdn.com/step3.js"> </script>
Todos sabemos que si hay dependencias en el paso 1, el paso 2 y el paso 3, debe ejecutarse estrictamente en este orden, de lo contrario puede ocurrir un error. El navegador puede solicitar archivos Step1 y Step3 en paralelo, pero el pedido se garantiza cuando se ejecuta. Si obtenemos el contenido del archivo del paso 1 y el paso 3 utilizando xmlhttprequest, debemos garantizar el orden correcto por nosotros mismos. Además, no olvides el paso2. El paso2 se puede ejecutar cuando el paso1 se descarga en forma no bloqueada, por lo que también debemos interferir con el paso2 y dejar que espere a que el paso 1 se complete antes de ejecutar.
Si ya tenemos un conjunto completo de herramientas para generar etiquetas <script> para diferentes páginas en el sitio web, necesitamos ajustar este conjunto de herramientas para hacer cambios en <script> etiquetas:
La copia del código es la siguiente:
<script>
SchedulerEmotescript ('http://cdn.com/step1.js');
</script>
<script>
programarInlinescript (Function Code () {
(función step2 () {}) ();
});
</script>
<script>
SchedulerEmotescript ('http://cdn.com/step3.js');
</script>
Necesitamos implementar las dos funciones SchedulerEmotescript y ProgryInlinescript, y asegurarnos de que se definan antes de la primera etiqueta <Script> que hace referencia al archivo de script externo, y luego las etiquetas <script> restantes se reescribirán en el formulario anterior. Tenga en cuenta que la función STEP2 que se ejecutó inmediatamente se colocó en una función de código más grande. La función del código no se ejecutará, es solo un contenedor, de modo que el código de step2 original se pueda retener sin escapar, pero no se ejecutará de inmediato.
A continuación, necesitamos implementar un mecanismo completo para garantizar que el contenido del archivo descargado por SchedulerEmotescript en función de la dirección y el código obtenido directamente por ProgryInlinescript se pueda ejecutar uno por uno en el orden correcto. No daré el código detallado aquí. Si está interesado, puede implementarlo usted mismo.
Verificación del número de línea
Obtener contenido a través de CORS e inyectar código en la página puede romper las restricciones de seguridad, pero introducirá un nuevo problema, es decir, conflictos de números de línea. Originalmente, el archivo de script único podría ubicarse a través de Error.script, y luego el número de línea único podría ubicarse a través de Error.line. Ahora, dado que todos los códigos integrados en la página son todos los códigos, múltiples etiquetas <script> no se pueden distinguir por error.script. Sin embargo, el número de línea dentro de cada etiqueta <Script> se calcula a partir de 1, lo que resulta en que no se pueda usar información de excepción para ubicar la ubicación del código fuente donde se encuentra el error.
Para evitar conflictos de números de línea, podemos desperdiciar algunos números de línea para que los intervalos de número de línea utilizados por el código real en cada etiqueta <script> no se superpongan entre sí. Por ejemplo, suponiendo que el código real en cada etiqueta <script> no exceda las 1000 líneas, luego puedo dejar que el código en la primera etiqueta <script> ocupe la línea 11000, el código en la segunda etiqueta <script> Tag Occupe 10012000 (1000 líneas vacías se insertaron antes), el código en la tercera etiqueta <script> la etiqueta 20013000 (2000 líneas vacías se insertaron antes) y así. Luego usamos el atributo de datos-* para registrar esta información para una fácil verificación de retroceso.
La copia del código es la siguiente:
<guión
data-src = "http://cdn.com/step1.js"
data-line-start = "1"
>
// código para el paso 1
</script>
<script data-line-start = "1001">
// '/n' * 1000
// código para el paso 2
</script>
<guión
data-src = "http://cdn.com/step3.js"
data-line-start = "2001"
>
// '/n' * 2000
// código para el paso 3
</script>
Después de este procesamiento, si un error de error es 3005, significa que el error real.
Por supuesto, dado que no podemos garantizar que cada archivo de script tenga solo 1000 líneas, también es posible que algunos archivos de script sean significativamente inferiores a 1000 líneas, por lo que no es necesario asignar fijamente un intervalo de línea de 1000 a cada etiqueta <script>. Podemos asignar intervalos basados en el número real de líneas de script, solo asegurarnos de que los intervalos utilizados por cada etiqueta <script> no se superpongan.
atributo de Crossorigin
Las restricciones de seguridad impuestas por los navegadores en el contenido de diferentes fuentes no se limitan a las etiquetas <script>. Dado que XMLHTTPREQUEST puede romper esta limitación a través de CORS, ¿por qué los recursos se hacen referencia directamente a través de etiquetas no permitidas? Esto ciertamente está bien.
La limitación de referirse a diferentes archivos de script de origen para etiquetas <script> también se aplica a referirse a diferentes archivos de imagen de origen para etiquetas <img>. Si una etiqueta <MG> es una fuente diferente, una vez utilizada en el dibujo <Canvas>, <Canvas> se convertirá en un estado de solo escritura, asegurando que el sitio web no pueda robar datos de imágenes no autorizados de diferentes fuentes a través de JavaScript. Más tarde, la etiqueta <img> resolvió este problema al introducir el atributo de Crossorigin. Si Crossorigin = "Anónimo", es equivalente a Cors anónimo; Si Crossorigin = "Use-Credentials", es equivalente a un CORS certificado.
Dado que la etiqueta <img> puede hacer esto, ¿por qué la etiqueta <script> no puede hacer esto? Entonces, el fabricante del navegador agregó el mismo atributo de Crossorigin a la etiqueta <script> para resolver las restricciones de seguridad anteriores. Ahora el soporte de Chrome y Firefox para esta propiedad es completamente gratuito. Safari tratará a Crossorigin = "Anónimo" como Crossorigin = "Use-Credentials", y el resultado es que si el servidor solo admite CORS anónimo, Safari tratará la autenticación como falla. Debido a que el servidor CDN está diseñado para devolver solo contenido estático por razones de rendimiento, es imposible devolver dinámicamente el encabezado HTTP requerido para autenticar CORS en función de las solicitudes. Safari es equivalente a no poder usar esta función para resolver el problema anterior.
Resumir
El manejo de excepciones de JavaScript se ve simple y no es diferente de otros idiomas, pero no es tan fácil atrapar todas las excepciones y analizar las propiedades. Ahora, aunque algunos servicios de terceros proporcionan servicios similares a Google Analytics que atrapan excepciones de JavaScript, si desea comprender los detalles y principios, aún tiene que hacerlo usted mismo.