Maison >interface Web >js tutoriel >Gestion des exceptions JavaScript explication détaillée_compétences javascript

Gestion des exceptions JavaScript explication détaillée_compétences javascript

WBOY
WBOYoriginal
2016-05-16 16:15:30935parcourir

Les ingénieurs front-end savent tous que JavaScript possède des capacités de base de gestion des exceptions. Nous pouvons lancer une nouvelle erreur(), et le navigateur lancera également une exception lorsque nous commettons une erreur lors de l'appel de l'API. Mais on estime que la plupart des ingénieurs front-end n'ont jamais envisagé de collecter ces informations anormales

Quoi qu'il en soit, tant que l'erreur JavaScript ne réapparaît pas après l'actualisation, l'utilisateur peut résoudre le problème en actualisant et le navigateur ne plantera pas. Faites simplement comme si cela ne s'était pas produit. Cette hypothèse était vraie avant que les applications à page unique ne deviennent populaires. L'état de l'application Single Page actuelle devient extrêmement compliqué après une période d'exécution. L'utilisateur peut avoir effectué plusieurs opérations de saisie avant d'arriver ici. Doit-elle être actualisée alors qu'elle est censée être actualisée ? Ne faudrait-il pas entièrement refaire l’opération précédente ? Nous devons donc toujours capturer et analyser ces informations d'exception, puis nous pouvons modifier le code pour éviter d'affecter l'expérience utilisateur.

Comment détecter les exceptions

Nous avons écrit notre propre throw new Error(). Bien sûr, nous pouvons l'attraper si nous le voulons, car nous savons exactement où throw est écrit. Cependant, les exceptions qui se produisent lors de l'appel des API du navigateur ne sont pas nécessairement faciles à détecter. Certaines API sont écrites dans les normes pour lever des exceptions, et certaines API ne sont lancées que par des navigateurs individuels en raison de différences ou de défauts d'implémentation. Pour le premier, nous pouvons également l'attraper via try-catch. Pour le second, nous devons écouter l'exception globale puis l'attraper.

essayer-attraper

Si certaines API de navigateur sont connues pour générer des exceptions, nous devons alors placer l'appel en try-catch pour empêcher l'ensemble du programme d'entrer dans un état illégal en raison d'erreurs. Par exemple, window.localStorage est une telle API. Elle lèvera une exception après que l'écriture des données dépasse la limite de capacité. Ce sera également le cas dans le mode de navigation privée de Safari.

Copier le code Le code est le suivant :

essayez {
localStorage.setItem('date', Date.now());
} attraper (erreur) {
reportError(erreur);
>


Un autre cas d’utilisation courant du try-catch est celui des rappels. Étant donné que le code de la fonction de rappel est hors de notre contrôle, nous n'avons aucune idée de la qualité du code ni si d'autres API qui lanceront des exceptions seront appelées. Afin d'éviter que d'autres codes après l'appel du rappel ne puissent s'exécuter en raison d'erreurs de rappel, il est nécessaire de remettre l'appel dans try-catch.

Copier le code Le code est le suivant :

auditeurs.forEach (fonction (auditeur) {
essayez {
auditeur();
} attraper (erreur) {
reportError(erreur);
>
});


window.onerror

Pour les zones qui ne sont pas couvertes par try-catch, si une exception se produit, elle ne peut être interceptée que via window.onerror.

Copier le code Le code est le suivant :

window.onerror =
fonction (message d'erreur, scriptURI, numéro de ligne) {
rapportErreur({
message : message d'erreur,
script : scriptURI,
ligne : numéro de ligne
});
>


Faites attention à ne pas être intelligent et utilisez window.addEventListener ou window.attachEvent pour écouter window.onerror. De nombreux navigateurs implémentent uniquement window.onerror, ou seule l'implémentation de window.onerror est standard. Considérant que le projet de norme définit également window.onerror, nous pouvons simplement utiliser window.onerror.

Attributs perdus

Supposons que nous ayons une fonction reportError qui collecte les exceptions capturées, puis les envoie par lots au stockage côté serveur pour interrogation et analyse. Quelles informations souhaitons-nous collecter ? Les informations les plus utiles incluent : le type d'erreur (nom), le message d'erreur (message), l'adresse du fichier de script (script), le numéro de ligne (ligne), le numéro de colonne (colonne) et la trace de la pile (pile). Si une exception est interceptée via try-catch, ces informations se trouvent sur l'objet Error (pris en charge par les navigateurs grand public), donc reportError peut également collecter ces informations. Mais si elle est capturée via window.onerror, nous savons tous que cette fonction événementielle n'a que 3 paramètres, donc les informations inattendues de ces 3 paramètres sont perdues.

Message sérialisé

Si l'objet Error est créé par nous-mêmes, alors error.message est contrôlé par nous. Fondamentalement, quoi que nous mettions dans error.message, le premier paramètre (message) de window.onerror le sera. (Le navigateur apportera en fait de légères modifications, comme l'ajout du préfixe « Erreur non détectée : ».) Par conséquent, nous pouvons sérialiser les propriétés qui nous intéressent (telles que JSON.Stringify) et les stocker dans error.message, puis les lire. dans window.onerror Retirez-le et désérialisez-le. Bien entendu, cela se limite aux objets Error que nous créons nous-mêmes.

Le cinquième paramètre

Les fabricants de navigateurs connaissent également les limitations auxquelles les utilisateurs sont confrontés lorsqu'ils utilisent window.onerror, ils ont donc commencé à ajouter de nouveaux paramètres à window.onerror. Considérant que seul le numéro de ligne mais aucun numéro de colonne ne semble pas très symétrique, IE ajoute d'abord le numéro de colonne et le met dans le quatrième paramètre. Cependant, tout le monde se soucie davantage de savoir s'ils peuvent obtenir la pile complète, donc Firefox a déclaré qu'il serait préférable de mettre la pile dans le cinquième paramètre. Mais Chrome a déclaré qu'il est préférable de placer l'intégralité de l'objet Error dans le cinquième paramètre. Vous pouvez lire toutes les propriétés de votre choix, y compris les propriétés personnalisées. En conséquence, Chrome a évolué plus rapidement et a implémenté une nouvelle signature window.onerror dans Chrome 30, ce qui a conduit à la rédaction du projet standard en conséquence.

Copier le code Le code est le suivant :

window.onerror = fonction (
Message d'erreur,
scriptURI,
numéro de ligne,
numéro de colonne,
erreur
) {
si (erreur) {
reportError(erreur);
} autre {
rapportErreur({
message : message d'erreur,
script : scriptURI,
ligne : numéro de ligne,
colonne : numéro de colonne
});
>
>


Régularisation d'attribut

Les noms des attributs de l'objet Error dont nous avons parlé précédemment sont basés sur la méthode de dénomination de Chrome. Cependant, différents navigateurs nomment les attributs de l'objet Error différemment. Par exemple, l'adresse du fichier de script est appelée script dans Chrome mais est appelée nom de fichier dans Firefox. . Par conséquent, nous avons également besoin d'une fonction spéciale pour normaliser l'objet Error, c'est-à-dire pour mapper différents noms d'attributs à des noms d'attributs unifiés. Pour des méthodes spécifiques, veuillez vous référer à cet article. Même si les implémentations des navigateurs seront mises à jour, la maintenance manuelle d’une telle table de mappage n’est pas trop difficile.

Similaire au format de trace de pile. Cet attribut enregistre une pile d'informations sur les exceptions sous forme de texte brut. Étant donné que le format de texte utilisé par chaque navigateur est différent, il est également nécessaire de maintenir manuellement une expression régulière pour extraire la fonction de chaque cadre du texte brut. identifiant), fichier (script), numéro de ligne (ligne) et numéro de colonne (colonne).

Restrictions de sécurité

Si vous avez également rencontré une erreur avec le message 'Erreur de script', vous comprendrez de quoi je parle. Il s'agit en fait d'une limitation du navigateur pour les fichiers de script d'origines différentes. La raison de cette restriction de sécurité est la suivante : en supposant que le HTML renvoyé par une banque en ligne après la connexion d'un utilisateur est différent du HTML vu par les utilisateurs anonymes, un site Web tiers peut insérer l'URI de la banque en ligne dans le script. attribut src. Bien entendu, HTML ne peut pas être analysé comme JS, le navigateur lancera donc une exception et le site Web tiers pourra déterminer si l'utilisateur est connecté en analysant l'emplacement de l'exception. Pour cette raison, le navigateur filtre toutes les exceptions levées par les fichiers de script provenant de différentes sources jusqu'à ce qu'il ne reste qu'un seul message inchangé tel que « Erreur de script » et que tous les autres attributs disparaissent.

Pour les sites Web d'une certaine envergure, il est normal que les fichiers scripts soient placés sur un CDN avec des sources différentes. Désormais, même si vous créez votre propre petit site Web, des frameworks courants tels que jQuery et Backbone peuvent directement référencer les versions sur les CDN publics pour accélérer les téléchargements des utilisateurs. Cette restriction de sécurité pose donc quelques problèmes, ce qui fait que les informations d'exception que nous collectons auprès de Chrome et Firefox sont des « erreurs de script » inutiles.

CORS

Pour contourner cette restriction, assurez-vous simplement que le fichier script et la page elle-même ont la même origine. Mais mettre le fichier script sur un serveur qui n'est pas accéléré par CDN ne ralentira pas la vitesse de téléchargement de l'utilisateur ? Une solution consiste à continuer à placer le fichier de script sur le CDN, à utiliser XMLHttpRequest pour télécharger le contenu via CORS, puis à créer une balise <script> Le code intégré dans la page provient bien entendu de la même source. </p> <p>Cela semble simple, mais il y a de nombreux détails à mettre en œuvre. Pour utiliser un exemple simple : </p> <p></p> <div class="codetitle"> <span><a style="CURSOR: pointer" data="85881" class="copybut" id="copybut85881" onclick="doCopy('code85881')"><u>Copier le code</u></a></span> Le code est le suivant :</div> <div class="codebody" id="code85881"> <br> <script src="<a href="http://cdn.com/step1.js"></script">http://cdn.com/step1.js"></script</a>><br> <script><br> (function step2() {})();<br> </script>

data-src="http://cdn.com/step3.js"
data-line-start="2001"
>
// 'n' *2000
// code pour l'étape 3



Après ce traitement, si le error.line d'une erreur est 3005, cela signifie que le error.script réel doit être 'http://cdn.com/step3.js' et le error.line réel doit être 5 . Nous pouvons effectuer cette vérification inverse du numéro de ligne dans la fonction reportError mentionnée précédemment.

Bien sûr, puisque nous ne pouvons pas garantir que chaque fichier de script ne contient que 1 000 lignes et que certains fichiers de script peuvent contenir nettement moins de 1 000 lignes, il n'est pas nécessaire d'attribuer une plage fixe de 1 000 lignes à chaque balise