web-dev-qa-db-fra.com

Gestion globale des erreurs JavaScript

Je voudrais attraper chaque erreur de fonction non définie levée. Existe-t-il une fonction globale de traitement des erreurs en JavaScript? Le cas d'utilisation détecte des appels de fonction flash qui ne sont pas définis.

333
Bob

Est-ce que cela vous aide:

<script type="text/javascript">
window.onerror = function() {
    alert("Error caught");
};

xxx();
</script>

Je ne sais pas comment il gère les erreurs Flash ...

Mise à jour: cela ne fonctionne pas dans Opera, mais je pirate Dragonfly pour le savoir. La suggestion concernant le piratage de Dragonfly est venue de cette question:

Mimic Window. Onerror in Opera en utilisant javascript

186
Ionuț G. Stan

Comment corriger les erreurs Javascript non gérées

Affectez l'événement window.onerror à un gestionnaire d'événements tel que:

<script type="text/javascript">
window.onerror = function(msg, url, line, col, error) {
   // Note that col & error are new to the HTML 5 spec and may not be 
   // supported in every browser.  It worked for me in Chrome.
   var extra = !col ? '' : '\ncolumn: ' + col;
   extra += !error ? '' : '\nerror: ' + error;

   // You can view the information in an alert to see things working like this:
   alert("Error: " + msg + "\nurl: " + url + "\nline: " + line + extra);

   // TODO: Report this error via ajax so you can keep track
   //       of what pages have JS issues

   var suppressErrorAlert = true;
   // If you return true, then error alerts (like in older versions of 
   // Internet Explorer) will be suppressed.
   return suppressErrorAlert;
};
</script>

Comme indiqué dans le code, si la valeur de retour de window.onerror est true, le navigateur doit alors supprimer l’affichage d’un dialogue d’alerte.

Quand l'événement window.onerror est-il déclenché?

En un mot, l'événement est déclenché lorsque 1.) il existe une exception non capturée ou 2.) une erreur de compilation survient.

exceptions non capturées

  • jeter "quelques messages"
  • call_something_undefined ();
  • cross_Origin_iframe.contentWindow.document ;, une exception de sécurité

erreur de compilation

  • <script>{</script>
  • <script>for(;)</script>
  • <script>"oops</script>
  • setTimeout("{", 10);, il tentera de compiler le premier argument sous forme de script

Navigateurs supportant window.onerror

  • Chrome 13+
  • Firefox 6.0+
  • Internet Explorer 5.5+
  • Opera 11.60+
  • Safari 5.1+

Capture d'écran:

Exemple du code onerror ci-dessus en action après l'ajout de celui-ci à une page de test:

<script type="text/javascript">
call_something_undefined();
</script>

Javascript alert showing error information detailed by the window.onerror event

JSFiddle:

https://jsfiddle.net/nzfvm44d/

Références:

622
Sam

traitement d'erreur sophistiqué

Si votre gestion des erreurs est très sophistiquée et peut donc générer une erreur elle-même, il est utile d'ajouter un drapeau indiquant si vous êtes déjà en "mode de gestion des erreurs". Ainsi:

var appIsHandlingError = false;

window.onerror = function() {
    if (!appIsHandlingError) {
        appIsHandlingError = true;
        handleError();
    }
};

function handleError() {
    // graceful error handling
    // if successful: appIsHandlingError = false;
}

Sinon, vous pourriez vous retrouver dans une boucle infinie.

38
SunnyRed

Essayez Atatus , qui fournit un suivi avancé des erreurs et une surveillance des utilisateurs réels pour les applications Web modernes.

https://www.atatus.com/

Laissez-moi vous expliquer comment obtenir des stacktraces raisonnablement complètes dans tous les navigateurs.

Gestion des erreurs en JavaScript

Modern Chrome et Opera prennent entièrement en charge les spécifications de brouillon HTML 5 pour ErrorEvent et window.onerror. Dans ces deux navigateurs, vous pouvez utiliser window.onerror ou vous lier correctement à l'événement 'error':

// Only Chrome & Opera pass the error object.
window.onerror = function (message, file, line, col, error) {
    console.log(message, "from", error.stack);
    // You can send data to your server
    // sendError(data);
};
// Only Chrome & Opera have an error attribute on the event.
window.addEventListener("error", function (e) {
    console.log(e.error.message, "from", e.error.stack);
    // You can send data to your server
    // sendError(data);
})

Malheureusement, Firefox, Safari et IE existent toujours et nous devons également les prendre en charge. Le stacktrace n'étant pas disponible dans window.onerror, nous devons effectuer un peu plus de travail.

Il s’avère que la seule chose que nous puissions faire pour obtenir stacktraces à partir d’erreurs consiste à envelopper tout notre code dans un bloc try{ }catch(e){ }, puis à regarder e.stack. Nous pouvons rendre le processus un peu plus facile avec une fonction appelée wrap qui prend une fonction et renvoie une nouvelle fonction avec une bonne gestion des erreurs.

function wrap(func) {
    // Ensure we only wrap the function once.
    if (!func._wrapped) {
        func._wrapped = function () {
            try{
                func.apply(this, arguments);
            } catch(e) {
                console.log(e.message, "from", e.stack);
                // You can send data to your server
                // sendError(data);
                throw e;
            }
        }
    }
    return func._wrapped;
};

Cela marche. Toutes les fonctions que vous encapsulerez manuellement auront une bonne gestion des erreurs, mais il s'avère que nous pouvons le faire pour vous automatiquement dans la plupart des cas.

En modifiant la définition globale de addEventListener pour qu'elle encapsule automatiquement le rappel, nous pouvons automatiquement insérer try{ }catch(e){ } autour de la plupart du code. Cela permet au code existant de continuer à fonctionner, mais ajoute un suivi des exceptions de haute qualité.

var addEventListener = window.EventTarget.prototype.addEventListener;
window.EventTarget.prototype.addEventListener = function (event, callback, bubble) {
    addEventListener.call(this, event, wrap(callback), bubble);
}

Nous devons également nous assurer que removeEventListener continue de fonctionner. Pour le moment, ce n'est pas le cas, car l'argument de addEventListener a été modifié. Encore une fois, nous devons seulement résoudre ce problème sur l’objet prototype:

var removeEventListener = window.EventTarget.prototype.removeEventListener;
window.EventTarget.prototype.removeEventListener = function (event, callback, bubble) {
    removeEventListener.call(this, event, callback._wrapped || callback, bubble);
}

Transmettre les données d'erreur à votre backend

Vous pouvez envoyer des données d'erreur à l'aide de la balise d'image comme suit

function sendError(data) {
    var img = newImage(),
        src = 'http://yourserver.com/jserror&data=' + encodeURIComponent(JSON.stringify(data));

    img.crossOrigin = 'anonymous';
    img.onload = function success() {
        console.log('success', data);
    };
    img.onerror = img.onabort = function failure() {
        console.error('failure', data);
    };
    img.src = src;
}

Clause de non-responsabilité: Je suis un développeur Web chez https://www.atatus.com/ .

22
Fizer Khan

Il semble que window.onerror ne donne pas accès à toutes les erreurs possibles. Plus précisément, il ignore:

  1. <img> erreurs de chargement (réponse> = 400).
  2. <script> erreurs de chargement (réponse> = 400).
  3. erreurs globales si vous avez beaucoup d'autres bibliothèques dans votre application manipulant également window.onerror d'une manière inconnue (jquery, angular, etc.).
  4. probablement beaucoup de cas que je n'ai pas rencontrés après avoir exploré cela maintenant (iframes, débordement de pile, etc.).

Voici le début d'un script qui détecte bon nombre de ces erreurs afin que vous puissiez ajouter un débogage plus robuste à votre application pendant le développement.

(function(){

/**
 * Capture error data for debugging in web console.
 */

var captures = [];

/**
 * Wait until `window.onload`, so any external scripts
 * you might load have a chance to set their own error handlers,
 * which we don't want to override.
 */

window.addEventListener('load', onload);

/**
 * Custom global function to standardize 
 * window.onerror so it works like you'd think.
 *
 * @see http://www.quirksmode.org/dom/events/error.html
 */

window.onanyerror = window.onanyerror || onanyerrorx;

/**
 * Hook up all error handlers after window loads.
 */

function onload() {
  handleGlobal();
  handleXMLHttp();
  handleImage();
  handleScript();
  handleEvents();
}

/**
 * Handle global window events.
 */

function handleGlobal() {
  var onerrorx = window.onerror;
  window.addEventListener('error', onerror);

  function onerror(msg, url, line, col, error) {
    window.onanyerror.apply(this, arguments);
    if (onerrorx) return onerrorx.apply(null, arguments);
  }
}

/**
 * Handle ajax request errors.
 */

function handleXMLHttp() {
  var sendx = XMLHttpRequest.prototype.send;
  window.XMLHttpRequest.prototype.send = function(){
    handleAsync(this);
    return sendx.apply(this, arguments);
  };
}

/**
 * Handle image errors.
 */

function handleImage() {
  var ImageOriginal = window.Image;
  window.Image = ImageOverride;

  /**
   * New `Image` constructor. Might cause some problems,
   * but not sure yet. This is at least a start, and works on chrome.
   */

  function ImageOverride() {
    var img = new ImageOriginal;
    onnext(function(){ handleAsync(img); });
    return img;
  }
}

/**
 * Handle script errors.
 */

function handleScript() {
  var HTMLScriptElementOriginal = window.HTMLScriptElement;
  window.HTMLScriptElement = HTMLScriptElementOverride;

  /**
   * New `HTMLScriptElement` constructor.
   *
   * Allows us to globally override onload.
   * Not ideal to override stuff, but it helps with debugging.
   */

  function HTMLScriptElementOverride() {
    var script = new HTMLScriptElement;
    onnext(function(){ handleAsync(script); });
    return script;
  }
}

/**
 * Handle errors in events.
 *
 * @see http://stackoverflow.com/questions/951791/javascript-global-error-handling/31750604#31750604
 */

function handleEvents() {
  var addEventListenerx = window.EventTarget.prototype.addEventListener;
  window.EventTarget.prototype.addEventListener = addEventListener;
  var removeEventListenerx = window.EventTarget.prototype.removeEventListener;
  window.EventTarget.prototype.removeEventListener = removeEventListener;

  function addEventListener(event, handler, bubble) {
    var handlerx = wrap(handler);
    return addEventListenerx.call(this, event, handlerx, bubble);
  }

  function removeEventListener(event, handler, bubble) {
    handler = handler._witherror || handler;
    removeEventListenerx.call(this, event, handler, bubble);
  }

  function wrap(fn) {
    fn._witherror = witherror;

    function witherror() {
      try {
        fn.apply(this, arguments);
      } catch(e) {
        window.onanyerror.apply(this, e);
        throw e;
      }
    }
    return fn;
  }
}

/**
 * Handle image/ajax request errors generically.
 */

function handleAsync(obj) {
  var onerrorx = obj.onerror;
  obj.onerror = onerror;
  var onabortx = obj.onabort;
  obj.onabort = onabort;
  var onloadx = obj.onload;
  obj.onload = onload;

  /**
   * Handle `onerror`.
   */

  function onerror(error) {
    window.onanyerror.call(this, error);
    if (onerrorx) return onerrorx.apply(this, arguments);
  };

  /**
   * Handle `onabort`.
   */

  function onabort(error) {
    window.onanyerror.call(this, error);
    if (onabortx) return onabortx.apply(this, arguments);
  };

  /**
   * Handle `onload`.
   *
   * For images, you can get a 403 response error,
   * but this isn't triggered as a global on error.
   * This sort of standardizes it.
   *
   * "there is no way to get the HTTP status from a 
   * request made by an img tag in JavaScript."
   * @see http://stackoverflow.com/questions/8108636/how-to-get-http-status-code-of-img-tags/8108646#8108646
   */

  function onload(request) {
    if (request.status && request.status >= 400) {
      window.onanyerror.call(this, request);
    }
    if (onloadx) return onloadx.apply(this, arguments);
  }
}

/**
 * Generic error handler.
 *
 * This shows the basic implementation, 
 * which you could override in your app.
 */

function onanyerrorx(entity) {
  var display = entity;

  // ajax request
  if (entity instanceof XMLHttpRequest) {
    // 400: http://example.com/image.png
    display = entity.status + ' ' + entity.responseURL;
  } else if (entity instanceof Event) {
    // global window events, or image events
    var target = entity.currentTarget;
    display = target;
  } else {
    // not sure if there are others
  }

  capture(entity);
  console.log('[onanyerror]', display, entity);
}

/**
 * Capture stuff for debugging purposes.
 *
 * Keep them in memory so you can reference them
 * in the chrome debugger as `onanyerror0` up to `onanyerror99`.
 */

function capture(entity) {
  captures.Push(entity);
  if (captures.length > 100) captures.unshift();

  // keep the last ones around
  var i = captures.length;
  while (--i) {
    var x = captures[i];
    window['onanyerror' + i] = x;
  }
}

/**
 * Wait til next code execution cycle as fast as possible.
 */

function onnext(fn) {
  setTimeout(fn, 0);
}

})();

Cela pourrait être utilisé comme ceci:

window.onanyerror = function(entity){
  console.log('some error', entity);
};

Le script complet a une implémentation par défaut qui tente d’imprimer une version "d'affichage" semi-lisible de l'entité/erreur qu'il reçoit. Peut être utilisé comme source d'inspiration pour un gestionnaire d'erreurs spécifique à une application. L'implémentation par défaut conserve également une référence aux 100 dernières entités d'erreur. Vous pouvez donc les inspecter dans la console Web après leur apparition, comme suit:

window.onanyerror0
window.onanyerror1
...
window.onanyerror99

Remarque: Ceci fonctionne en surchargeant les méthodes sur plusieurs constructeurs de navigateur/natifs. Cela peut avoir des effets secondaires inattendus. Cependant, il a été utile d’utiliser pendant le développement pour savoir où des erreurs se produisent, d’envoyer des journaux à des services tels que NewRelic ou Sentry pendant le développement afin de pouvoir un niveau plus profond. Il peut ensuite être désactivé en production.

J'espère que cela t'aides.

16
Lance Pollard
// display error messages for a page, but never more than 3 errors
window.onerror = function(msg, url, line) {
if (onerror.num++ < onerror.max) {
alert("ERROR: " + msg + "\n" + url + ":" + line);
return true;
}
}
onerror.max = 3;
onerror.num = 0;
6
GibboK

Il faut également conserver le rappel onerror précédemment associé

<script type="text/javascript">

(function() {
    var errorCallback = window.onerror;
    window.onerror = function () {
        // handle error condition
        errorCallback && errorCallback.apply(this, arguments);
    };
})();

</script>
6
Apoorv Saxena

Si vous voulez un moyen unifié de gérer à la fois les erreurs non détectées et les refus de promesses non gérées, vous pouvez jeter un oeil sur bibliothèque non capturée .

EDIT

<script type="text/javascript" src=".../uncaught/lib/index.js"></script>

<script type="text/javascript">
    uncaught.start();
    uncaught.addListener(function (error) {
        console.log('Uncaught error or rejection: ', error.message);
    });
</script>

Il écoute window . non manipulé en plus de window.onerror.

3

Je recommanderais d'essayer Trackjs .

C'est une erreur de journalisation en tant que service.

C'est incroyablement simple à mettre en place. Ajoutez simplement une ligne <script> à chaque page et le tour est joué. Cela signifie également qu'il sera incroyablement simple à supprimer si vous décidez que vous ne l'aimez pas.

Il existe d'autres services tels que Sentry (qui est open-source si vous pouvez héberger votre propre serveur), mais il ne fait pas ce que Trackjs fait. Trackjs enregistre les interactions de l'utilisateur entre son navigateur et votre serveur Web, ce qui vous permet de suivre les étapes qui ont provoqué l'erreur, par opposition à une référence de fichier et de numéro de ligne (et éventuellement à une trace de pile).

3
kane

Vous écoutez l'événement onerror en assignant une fonction à window.onerror:

 window.onerror = function (msg, url, lineNo, columnNo, error) {
        var string = msg.toLowerCase();
        var substring = "script error";
        if (string.indexOf(substring) > -1){
            alert('Script Error: See Browser Console for Detail');
        } else {
            alert(msg, url, lineNo, columnNo, error);
        }   
      return false; 
  };
1
Ali Azhar