Catching All JavaScript Errors in All Browsers

I recently wrote an article about the JavaScript onerror event. The onerror event is really powerful in that you can prevent all JavaScript errors from ever being shown to the user, as well as capturing each error seen by users and sending it to a server for logging. The major downside is that only the major browsers (IE and FireFox) support window.onerror, so we don’t get the same goodness in Safari, Opera, and other smaller browsers. I spent some time over the last week and devised a solution that will allow catching all errors in all browsers. However, it is rather onerous, so I present it here as a proof of concept, but hope that some of you can suggest ways to help improve it.

The sure-fire way to capture all errors in all browsers, is to put a try/catch statement inside each Function. Obviously, doing so would be ridiculous, even though you are trying to solve a huge problem: preventing and capturing JavaScript errors. However, you can instead create a proxy Function that handles the try/catch wrap for you. Instead of calling a Function/Method directly, you will use the proxy Function throughout your code. Inside the proxy, we put a try/catch statement to capture exceptions. The catch statement will send an AJAX message to log the error server-side, and return NULL. Otherwise the proxy Function will return the same value that would have normally been returned by executing the passed method. While, still onerous, this is probably a do-able solution:

Example 1: The call_user_method_array Function

/**
 * Calls the method, scoped to the passed object, with the set of parameters.
 *
 * @method call_user_method_array
 * @param method_name {String} Required. The method name on ``obj``.
 * @param obj {Object} Required. The object owning the method, that the method will also be scoped as.
 * @param paramarr {Array} Required. The collection of parameters.
 * @static
 */
var call_user_method_array = function(method_name, obj, paramarr) {
	try {
		return obj[method_name].apply(obj, paramarr || []);
	}
	catch (e) {
		window.onerror(e.message, window.location, '-1'); // use -1 for exceptions
		return null;
	}
};

I modeled the method after a similar method used by PHP. The method should be placed early in global namespace, and I would recommend abbreviating the name to no more than three characters as it will be called many, many times. Below are a few examples of how to use this method:

Example 2: How to Use call_user_method_array

// calling a method on window
var testFunc = function() {/* do something */ };
call_user_method_array('testFunc', window);

// calling a method on a string
var testString = 'This is a string';
var index = call_user_method_array('indexOf', testString, ['string']);

// calling a nested method
var bool = call_user_method_array('isIE', Core.Client);

Obviously, for this to work completely, all function calls need to be wrapped. That is probably too onerous, unless you are using a framework that does it for you (YUI 3), but it this would be useful to wrap complex or particularly buggy parts of your codebase.