webentwicklung-frage-antwort-db.com.de

JavaScript globale Fehlerbehandlung

Ich möchte jeden undefinierten Funktionsfehler abfangen. Gibt es eine globale Fehlerbehandlungsfunktion in JavaScript? Der Anwendungsfall ist das Abfangen von Funktionsaufrufen aus Flash, die nicht definiert sind.

333
Bob

Hilft Ihnen das:

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

xxx();
</script>

Ich bin mir nicht sicher, wie es mit Flash-Fehlern umgeht ...

Update: Es funktioniert nicht in Opera, aber ich hacke gerade Dragonfly, um zu sehen, was es bringt. Ein Vorschlag zum Hacken von Dragonfly kam von dieser Frage:

Fenster nachahmen. Fehler in Opera mit Javascript

186
Ionuț G. Stan

So fangen Sie unbehandelte Javascript-Fehler ab

Weisen Sie das Ereignis window.onerror Einem Ereignishandler wie dem folgenden zu:

<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>

Wenn der Rückgabewert von window.onerror, Wie im Code angegeben, true ist, sollte der Browser die Anzeige eines Warnungsdialogs unterdrücken.

Wann wird das window.onerror-Ereignis ausgelöst?

Kurz gesagt, das Ereignis wird ausgelöst, wenn entweder 1.) eine nicht erfasste Ausnahme vorliegt oder 2.) ein Fehler beim Kompilieren auftritt.

nicht erfasste Ausnahmen

  • werfen "einige Nachrichten"
  • call_something_undefined ();
  • cross_Origin_iframe.contentWindow.document ;, eine Sicherheitsausnahme

Kompilierungsfehler

  • <script>{</script>
  • <script>for(;)</script>
  • <script>"oops</script>
  • setTimeout("{", 10);, es wird versucht, das erste Argument als Skript zu kompilieren

Browser, die window.onerror unterstützen

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

Bildschirmfoto:

Beispiel für den obigen Fehlercode in Aktion, nachdem dieser einer Testseite hinzugefügt wurde:

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

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

JSFiddle:

https://jsfiddle.net/nzfvm44d/

Verweise:

622
Sam

ausgefeilte Fehlerbehandlung

Wenn Ihre Fehlerbehandlung sehr komplex ist und daher einen Fehler selbst auslösen kann, ist es hilfreich, ein Flag hinzuzufügen, das angibt, ob Sie sich bereits im "errorHandling-Mode" befinden. Wie so:

var appIsHandlingError = false;

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

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

Ansonsten könnten Sie sich in einer Endlosschleife befinden.

38
SunnyRed

Versuchen Sie Atatus , das Advanced Error Tracking und Real User Monitoring für moderne Web-Apps bietet.

https://www.atatus.com/

Lassen Sie mich erklären, wie Sie Stacktraces erhalten, die in allen Browsern einigermaßen vollständig sind.

Fehlerbehandlung in JavaScript

Modern Chrome und Opera) unterstützen die HTML 5-Entwurfsspezifikation für ErrorEvent und window.onerror vollständig. In diesen beiden Browsern können Sie entweder window.onerror verwenden oder an den ' Fehler 'Ereignis richtig:

// 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);
})

Leider gibt es Firefox, Safari und IE und wir müssen sie auch unterstützen. Da das Stacktrace in window.onerror nicht verfügbar ist, müssen wir ein bisschen mehr arbeiten.

Es stellt sich heraus, dass das einzige, was wir tun können, um Stacktraces von Fehlern zu erhalten, darin besteht, unseren gesamten Code in einen try{ }catch(e){ } -Block zu verpacken und dann e.stack zu betrachten. Wir können den Prozess etwas vereinfachen, indem wir eine Funktion namens wrap verwenden, die eine Funktion übernimmt und eine neue Funktion mit guter Fehlerbehandlung zurückgibt.

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;
};

Das funktioniert. Jede Funktion, die Sie manuell umbrechen, hat eine gute Fehlerbehandlung, aber es stellt sich heraus, dass wir dies in den meisten Fällen automatisch für Sie tun können.

Durch Ändern der globalen Definition von addEventListener, sodass der Rückruf automatisch umgebrochen wird, können wir try{ }catch(e){ } automatisch um den meisten Code einfügen. Dadurch kann vorhandener Code weiter verwendet werden, es wird jedoch eine hochwertige Ausnahmeverfolgung hinzugefügt.

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

Wir müssen auch sicherstellen, dass removeEventListener weiterarbeitet. Im Moment wird dies nicht der Fall sein, da das Argument für addEventListener geändert wurde. Auch hier müssen wir nur das prototype -Objekt reparieren:

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

Übertragen Sie Fehlerdaten an Ihr Backend

Sie können Fehlerdaten wie folgt mit dem Image-Tag senden

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;
}

Haftungsausschluss: Ich bin ein Webentwickler bei https://www.atatus.com/ .

22
Fizer Khan

Es scheint, dass window.onerror Nicht alle möglichen Fehler anzeigt. Insbesondere ignoriert es:

  1. <img> Ladefehler (Antwort> = 400).
  2. <script> Ladefehler (Antwort> = 400).
  3. globale Fehler, wenn Ihre App viele andere Bibliotheken enthält, die window.onerror ebenfalls auf unbekannte Weise manipulieren (jQuery, Angular usw.).
  4. wahrscheinlich sind viele Fälle, auf die ich nicht gestoßen bin, nachdem ich dies jetzt untersucht habe (iframes, Stapelüberlauf usw.).

Hier ist der Beginn eines Skripts, das viele dieser Fehler abfängt, damit Sie Ihrer App während der Entwicklung ein robusteres Debugging hinzufügen können.

(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);
}

})();

Es könnte so verwendet werden:

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

Das vollständige Skript hat eine Standardimplementierung, die versucht, eine teilweise lesbare "Anzeige" -Version der Entität/des Fehlers auszudrucken, die/der es empfängt. Kann als Inspiration für einen app-spezifischen Fehlerbehandler verwendet werden. Die Standardimplementierung behält auch einen Verweis auf die letzten 100 Fehlerentitäten bei, sodass Sie sie in der Webkonsole überprüfen können, nachdem sie wie folgt aufgetreten sind:

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

Hinweis: Dies funktioniert durch Überschreiben von Methoden in mehreren Browsern/nativen Konstruktoren. Dies kann unbeabsichtigte Nebenwirkungen haben. Es war jedoch hilfreich, während der Entwicklung zu verwenden, um herauszufinden, wo Fehler auftreten, Protokolle an Dienste wie NewRelic oder Sentry zu senden, damit wir Fehler während der Entwicklung messen können, und beim Staging, um Fehler zu beheben, an denen gerade gearbeitet wird eine tiefere Ebene. Es kann dann in der Produktion abgeschaltet werden.

Hoffe das hilft.

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

Man sollte auch den zuvor damit verbundenen onerror callback erhalten

<script type="text/javascript">

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

</script>
6
Apoorv Saxena

Wenn Sie eine einheitliche Methode zum Behandeln nicht erfasster Fehler und nicht erfasster Ablehnungen von Versprechungen wünschen, schauen Sie unter ncaught library nach.

[~ # ~] 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>

Es lauscht window . nhandledrejection zusätzlich zu window.onerror.

3

Ich würde empfehlen, Trackjs auszuprobieren.

Es handelt sich um eine Fehlerprotokollierung als Dienst.

Es ist erstaunlich einfach einzurichten. Fügen Sie jeder Seite eine <script> -Zeile hinzu und fertig. Dies bedeutet auch, dass es erstaunlich einfach ist, es zu entfernen, wenn Sie entscheiden, dass Sie es nicht mögen.

Es gibt andere Dienste wie Sentry (das ist Open Source, wenn Sie Ihren eigenen Server hosten können), aber es macht nicht das, was Trackjs macht. Trackjs zeichnet die Interaktion des Benutzers zwischen seinem Browser und Ihrem Webserver auf, sodass Sie tatsächlich die Benutzerschritte verfolgen können, die zum Fehler geführt haben, und nicht nur eine Datei- und Zeilennummernreferenz (und möglicherweise eine Stapelverfolgung).

3
kane

Sie hören das onerror-Ereignis ab, indem Sie window.onerror eine Funktion zuweisen:

 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