Window onError Event


Window.onerror is an obscure and little used event with surprising usefulness. Before the days of FireBug it was difficult to debug, in each browser, where an error occurred and why. Now that we have FireBug, most JavaScript works wonderfully in FireFox and decently in other browsers. And even with the robust debugging, there will still be user machines that were not tested against, who see JavaScript errors that you can never capture. The 'onerror' event allows for you to assign a Function to be called every time an error occurs in your JavaScript code, passing into the function the browser message, URL of the current page, and the line number that triggered the error, which improves your ability to debug in any browser. In addition to those benefits, assigning a Function to 'onerror', also allows you to prevent errors from bubbling to the browser, and showing those annoying browser popups that occur on JavaScript errors.

Surprisingly this event has been around since IE 4, Netscape 3, and FireFox 1, so it is well supported by current browsers, even though it is rarely used. Here is a simple example of how to use this method:

Example 1: Simple 'onerror' Function

// declare this early in your codebase
window.onerror = function(message, url, lineNumber) {
	// code to execute on an error
	return true; // prevents browser error messages
};

Something I am experimenting with is to include this code in a file ("error.js") right after I initialize my Framework. "error.js" contains my "onerror" listener, catching all errors and exception, which I can then use to send AJAX messages to the back-end to log all JavaScript errors. Moreover, if you use a client detection method (core.js (see Core.Client Object), then you can also log the browser and OS that caused the error. Using YUI connection manager you would do something like:

Example 2: Error Logging

window.onerror = function(message, url, lineNumber) {
	var params = [];
	params[0] = 'browser=' + Core.Client.browser;
	params[1] = 'data=' + navigator.userAgent + '|' + navigator.vendor + '|' + navigator.platform;
	params[2] = 'lineNumber=' + Core.Client.message;
	params[3] = 'message=' + Core.Client.lineNumber;
	params[4] = 'os=' + Core.Client.OS;
	params[5] = 'url=' + Core.Client.url;
	params[6] = 'version=' + Core.Client.version;
	
	try {
		YAHOO.util.Connect.asyncRequest('GET', 'logJavaScriptError.event?' + params.join('&'), function() {}, null);
	}
	catch(e) {
		// squelch, because we don't want to prevent method from returning true
	}
	
	return true;
};

In this case you are logging the line number, url, and browser error message, in additional to client information. I also go ahead and send all possible browser variables, for future parsing in case I could not properly discern the browser programatically. The AJAX request, is simply a fire-and-forget pattern, because we don't really care if it is successful or not, we assume that 99% of the time it will succeed, so that these errors are properly logged. If there is an exception thrown in the AJAX code, say by YUI because the URL is not found, then this method would not completely execute. However, if you wrap the AJAX in a try/catch, you can ensure that the end of the method is reached and 'TRUE' is returned, to prevent errors from being shown to the browser.

I have created a test page, which tries to use a non-existant variable, thereby throwing an error. One thing you'll probably notice is that you don't get that pesky JavaScript error message in IE, however, you also do not get any FireBug goodness in FireFox. For FireBug to detect errors, the error must be allowed to bubble to the browser, so you will probably want a constant to turn off/on a debug mode, so that you can still use FireBug for development.

I also played around with using Framework Event handlers, however, none of the Frameworks I tested (YUI, MooTools, and Prototype) special-case an event handler for "window.onerror". There are two problems with "window.onerror" that requires special-case event handling. The first problem is that when using event handlers, the callback Function will only be passed the Event Object, instead of the 3 parameters that should be passed. Second, returning 'TRUE' does not stop the error (as the callback Function is wrapped), nor does stopping propagation and/or bubbling, so you cannot prevent errors from bubbling to the browser. You will have to assign your error handling method, directly to "window.onerror", and replace any implementation that your Framework might use.

Fortunately, after doing a quick search through those sample Frameworks, I found that only YUI attempts to implement the "window.onerror" code, and only in their "logger.js" file. In the definition of the Logger Object, you can specify whether to use an 'onerror' callback or not. I believe then, it is relatively safe, to play around with this event.