Gestion globale des erreurs JavaScript

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

309
demandé sur sg7 2009-06-04 20:53:06

10 réponses

Cela vous aide-t-il:

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

xxx();
</script>

Je ne suis pas sûr de savoir comment il gère les erreurs Flash...

Mise à jour: cela ne fonctionne pas dans Opera, mais je pirate Dragonfly en ce moment pour voir ce qu'il obtient. Suggestion sur le piratage libellule est venu de cette question:

Fenêtre D'Imitation. onerror dans Opera en utilisant javascript

173
répondu Ionuț G. Stan 2017-05-23 11:55:10

Comment attraper les erreurs Javascript non gérées

Affecter la window.onerror événement à un gestionnaire d'événements comme:

<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 alors le navigateur devrait supprimer l'affichage d'une boîte de dialogue d'alerte.

Quand la fenêtre.feu D'événement onerror?

En un mot, l'événement est déclenché lorsque 1.) il y a une exception non interceptée ou 2.) une erreur de compilation se produit.

Ce type d'exception

  • lancer "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 comme un script

Navigateur supportant la fenêtre.onerror

  • Chrome 13 +
  • Firefox 6.0+
  • Internet Explorer 5.5 +
  • Opéra 11,60 +
  • Safari 5.1 +

Capture d'écran:

Exemple du code onerror ci-dessus en action après avoir ajouté ceci à une page de test:

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

Alerte Javascript montrant des informations d'erreur détaillées par la fenêtre.événement onerror

JSFiddle:

Https://jsfiddle.net/nzfvm44d/

Références:

589
répondu Sam 2017-05-23 12:10:45

Gestion sophistiquée des erreurs

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 indicateur indiquant si vous êtes déjà en "errorHandling-Mode". Comme ça:

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.

35
répondu SunnyRed 2011-07-30 18:31:44

Essayez Atatus qui fournit un suivi avancé des erreurs et une surveillance réelle des utilisateurs 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

Chrome moderne et Opera prennent entièrement en charge la spécification HTML 5 draft pour ErrorEvent et window.onerror. Dans ces deux navigateurs, vous pouvez soit utiliser window.onerror, soit vous lier à l'erreur événement correctement:

// 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 sont toujours là et nous devons les soutenir aussi. Comme le stacktrace n'est pas disponible dans window.onerror, nous devons faire un peu plus de travail.

, Il s'avère que la seule chose que nous pouvons faire pour obtenir stacktraces d'erreurs consiste à envelopper l'ensemble de notre code dans un try{ }catch(e){ } bloc et puis regardez 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 erreur manutention.

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 fonctionne. Toute fonction que vous enrouler manuellement aura une bonne gestion des erreurs, mais il s'avère que nous pouvons le faire pour vous, automatiquement, dans la plupart des cas.

En changeant la définition globale de addEventListener afin qu'elle enveloppe 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 conserve travailler. Pour le moment, ce ne sera pas parce que l'argument de addEventListener est changé. Encore une fois, nous avons seulement besoin de 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);
}

Transmettez les données d'erreur à votre backend

Vous pouvez envoyer des données d'erreur en utilisant la balise 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;
}

Avertissement: je suis un développeur web à https://www.atatus.com/.

21
répondu Fizer Khan 2015-08-01 05:40:06

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é ceci maintenant (iframes, débordement de pile, etc.).

Voici le début d'un script qui détecte beaucoup de ces erreurs, de sorte que vous pouvez 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);
}

})();

Il 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 essaie d'imprimer une version "affichage" semi-lisible de l'entité / erreur qu'il reçoit. Peut être utilisé comme source d'inspiration pour un gestionnaire d'erreur spécifique à l'application. L'implémentation par défaut conserve également une référence aux 100 dernières entités d'erreur, de sorte que vous pouvez les inspecter dans le console web après qu'ils se produisent comme:

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

Note: cela fonctionne en remplaçant les méthodes sur plusieurs constructeurs de navigateurs / natifs. Cela peut avoir des effets secondaires involontaires. Cependant, il a été utile d'utiliser pendant le développement, de déterminer où se produisent les erreurs, d'envoyer des journaux à des services comme NewRelic ou Sentry pendant le développement afin que nous puissions mesurer les erreurs pendant le développement, et lors de la mise en scène afin que nous puissions déboguer ce qui se passe à un niveau plus profond. Il peut ensuite être éteint dans production.

J'espère que cela aide.

11
répondu Lance Pollard 2018-01-16 12:29:45
// 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
répondu GibboK 2014-09-27 10:26:36

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>
5
répondu Apoorv Saxena 2016-05-30 13:19:06

Je recommande de donner Trackjs un essai.

C'est la journalisation des erreurs en tant que service.

C'est incroyablement simple à mettre en place. Ajoutez simplement une ligne à chaque page et c'est tout. Cela signifie également qu'il sera incroyablement simple à enlever si vous décidez que vous ne l'aimez pas.

Il existe d'autres services comme Sentry (qui est open-source si vous pouvez héberger votre propre serveur), mais il ne fait pas ce que fait Trackjs. Trackjs enregistre l'interaction de l'utilisateur entre son navigateur et votre serveur web afin que vous puissiez réellement tracer les étapes de l'utilisateur qui ont conduit à l'erreur, par opposition à une simple référence de numéro de fichier et de ligne (et peut-être une trace de pile).

3
répondu kane 2015-06-16 12:22:50

Si vous voulez un moyen unifié de gérer à la fois les erreurs non interceptées et les rejets de promesses non gérés, vous pouvez consulter la bibliothèque uncaught.

Modifier

<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 la fenêtre.unhandledrejection en plus de la fenêtre.onerror.

3
répondu Aleksandr Oleynikov 2016-11-24 10:44:52

Vous écoutez l'événement onerror en affectant 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
répondu Ali Azhar 2016-08-07 09:37:50