JavaScript Exception Handling

JavascriptException

Javascript Problem Overview


What is the best technique for catching ALL exceptions thrown within JavaScript?

Obviously, the best technique is to use try...catch. But with ansynchronous callbacks and so forth, that can get tricky.

I know IE and Gecko browsers support window.onerror, but what about Opera and Safari?

Here are a bunch of test-cases that I would like to have a central exception handling solution for:

// ErrorHandler-Test1
var test = null;
test.arg = 5;
// ErrorHandler-Test2
throw (new Error("Hello"));
// ErrorHandler-Test3
throw "Hello again";
// ErrorHandler-Test4
throw {
	myMessage: "stuff",
	customProperty: 5,
	anArray: [1, 2, 3]
};
// ErrorHandler-Test5
try {
	var test2 = null;
	test2.arg = 5;
} catch(e) {
	ErrorHandler.handleError(e);
}
// ErrorHandler-Test6
try {
	throw (new Error("Goodbye"));
} catch(e) {
	ErrorHandler.handleError(e);
}
// ErrorHandler-Test7
try {
	throw "Goodbye again";
} catch(e) {
	ErrorHandler.handleError(e);
}
// ErrorHandler-Test8
try {
	throw {
		myMessage: "stuff",
		customProperty: 5,
		anArray: [1, 2, 3]
	};
} catch(e) {
	ErrorHandler.handleError(e);
}

If you think of any other test-cases, please mention them. Several of these cases mention a ErrorHandler.handleError method. This is just a suggested guideline when using try...catch.

Javascript Solutions


Solution 1 - Javascript

If you use a library like jQuery for assigning all your event handlers, you can use a combination of window.onerror and wrapping the jQuery event handler code and on ready function with an error handling function (see: JavaScript Error Tracking: Why window.onerror Is Not Enough).

  • window.onerror: catches all errors in IE (and most errors in Firefox), but does nothing in Safari and Opera.

  • jQuery event handlers: catches jQuery event errors in all browsers.

  • jQuery ready function: catches initialisation errors in all browsers.

Solution 2 - Javascript

WebKit (Safari, Chrome, etc) now appears to support onerror.

Original post: As far as I know, WebKit/Safari does not support the onerror event. Which is a damn shame.

Solution 3 - Javascript

Actually, the jquery approach isn't so bad. See:

<http://docs.jquery.com/Events/error#fn>

and:

$(window).error(function(msg, url, line){
  $.post("js_error_log.php", { msg: msg, url: url, line: line });
});

Solution 4 - Javascript

Catch all exceptions with your own exception handler and use instanceof.

$("inuput").live({
    click : function (event) {
        try {
            if (somethingGoesWrong) {
                throw new MyException();
            }
        } catch (Exception) {
            new MyExceptionHandler(Exception);
        }
        
    }
});

function MyExceptionHandler(Exception) {
    if (Exception instanceof TypeError || 
     	Exception instanceof ReferenceError || 
 		Exception instanceof RangeError || 	
 		Exception instanceof SyntaxError || 	
   		Exception instanceof URIError ) {
     	throw Exception; // native error
     } else {
         // handle exception
     }
}

MyExcetpionHandler will throw native error as there is no try-catch block.

Visit <http://www.nczonline.net/blog/2009/03/10/the-art-of-throwing-javascript-errors-part-2/>

Solution 5 - Javascript

try-catch is not always the best solution. For example, in Chrome 7.0 you lose the nice stack trace in the console window. Rethrowing the exception does not help. I don't know of any solution which preserves stack traces and letting you react on exception.

Solution 6 - Javascript

With a little bit of work it's possible to get stacktraces that are reasonably complete in all browsers.

Modern Chrome and Opera (i.e. anything based around the Blink rendering engine) fully support the HTML 5 draft spec for ErrorEvent and window.onerror. In both of these browsers you can either use window.onerror, or (amazingly!) bind to the 'error' event properly:

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

Unfortunately Firefox, Safari and IE are still around and we have to support them too. As the stacktrace is not available in window.onerror we have to do a little bit more work.

It turns out that the only thing we can do to get stacktraces from errors is to wrap all of our code in a try{ }catch(e){ } block and then look at e.stack. We can make the process somewhat easier with a function called wrap that takes a function and returns a new function with good error handling.

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
                // sendData(data);
                throw e;
            }
        }
    }
    return func._wrapped;
};

This works. Any function that you wrap manually will have good error handling.

You can send data using image tag as follows

function sendData(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;
}

However you have to do backend to collect the data and front-end to visualise the data.

At Atatus, we are working on solving this problem. More than error tracking, Atatus provides real user monitoring.

> Give a try https://www.atatus.com/

Disclaimer: I am a web developer at Atatus.

Solution 7 - Javascript

It is true that with modern browsers, hooking window.onerror for errors that bubble all the way to the top along with adding jQuery event handlers for Ajax errors will catch practically all Error objects thrown in your client code. If you're manually setting up a handler for window.onerror, in modern browsers this is done with window.addEventListener('error', callback), while in IE8/9 you need to call window.attachEvent('onerror', callback).

Note that you should then consider the environment in which these errors are being handled, and the reason for doing so. It is one thing to catch as many errors as possible with their stacktraces, but the advent of modern F12 dev tools solves this use case when implementing and debugging locally. Breakpoints etc will give you more data than is available from the handlers, especially for errors thrown by third-party libraries which were loaded from CORS requests. You need to take additional steps to instruct the browser to provide this data.

The key issue is providing this data in production, as your users are guaranteed to run a far wider array of browsers and versions than you can possibly test, and your site/app will break in unexpected ways, no matter how much QA you throw at it.

To handle this, you need a production error tracker which picks up every error thrown in your user's browsers, as they use your code, and sends them to an endpoint where the data can be viewed by you and used to fix the bugs as they happen. At Raygun (disclaimer: I work at Raygun) we've put a bunch of effort into providing a great experience for this, as there's many pitfalls and issues to consider that a naive implementation will miss.

For instance, chances are you'll be bundling and minifying your JS assets, which means that errors thrown from minified code will have junk stacktraces with mangled variable names. For this, you need your build tool to generate source maps (we recommend UglifyJS2 for this part of the pipeline), and your error tracker to accept and process these, turning the mangled stacktraces back into human-readable ones. Raygun does all this out of the box, and includes an API endpoint to accept source maps as they are generated by your build process. This is key as they need to be kept non-public, otherwise anyone could unminify your code, negating its purpose.

The raygun4js client library also comes with window.onerror for both modern and legacy browsers, as well as jQuery hooks out-of-the-box, so to set this up you only need to add:

<script type="text/javascript" src="//cdn.raygun.io/raygun4js/raygun.min.js" </script> <script> Raygun.init('yourApiKey').attach(); </script>

There's also a bunch of functionality built-in including the ability to mutate the error payload before it is sent, adding tags and custom data, metadata on the user who saw the error. It also takes the pain out of getting good stack traces from the above-mentioned third-party CORS scripts, which solves the dreaded 'Script Error' (which contains no error message, and no stack trace).

A more crucial issue is that due to the huge audience on the web, your site will generate many thousands of duplicate instances of each error. An error tracking service like Raygun has smarts to roll these up into error groups so you don't drown in a flood of notifications, and lets you see each actual error ready to be fixed.

Solution 8 - Javascript

I was also looking for error handling and stacktrace and logging for user actions this is what i found hope this also helps you https://github.com/jefferyto/glitchjs

Solution 9 - Javascript

The best error handler:

try {
    // something
} catch(e) {
    window.location.href = "https://stackoverflow.com/search?q=[js] + " + e.message
}

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
Questionharley.333View Question on Stackoverflow
Solution 1 - JavascriptKarlView Answer on Stackoverflow
Solution 2 - JavascripteyelidlessnessView Answer on Stackoverflow
Solution 3 - JavascriptadamfiskView Answer on Stackoverflow
Solution 4 - JavascriptMyounghoonKimView Answer on Stackoverflow
Solution 5 - JavascriptwolfgangView Answer on Stackoverflow
Solution 6 - JavascriptFizer KhanView Answer on Stackoverflow
Solution 7 - JavascriptK. CravenView Answer on Stackoverflow
Solution 8 - JavascriptRamIndaniView Answer on Stackoverflow
Solution 9 - JavascriptRodrigo Alvaro Santo SD 6View Answer on Stackoverflow