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 giving you the ability to capture each error and send it to the server for logging. The major downside is that only the major browsers (IE and FireFox) support 'onerror', because of this you miss all the goodness in Safari, Opera, and other smaller browsers. I spent some time over the last week and devised a solution that will allow you to catch all errors in all browsers. However, it is rather onerous, so I present it here, 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 3 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);
