Global Error Handling

In object oriented programming it is common practice to throw exceptions for known error conditions. However, JavaScript lacks one essential feature to make consistent use of exceptions practical: There is no way have a fallback handler, which receives all exceptions that are not caught in the application code. The result is that uncaught exceptions show up in the browser and depending on the user’s preferences might even pop up an error dialog. Furthermore, in production systems it is often desirable to log all errors and send them back to the server to monitor the application.

Most browsers provide the window.onerror hook, which is supposed to act as a fallback error handler, but since it is not standardized, the implementations differ significantly.

window.onerror = function() {
  console.log(arguments);
  return true; // hide error from browser
}
throw new Error("Error");

onerror_firebug

Note that only the error message but not the exception object is available. The second and third parameters point to the URL, which raised the error and an error code. Both additional parameters are missing in Safari. Opera doesn’t support onerror at all.

Since we can’t rely on onerror, we decided to provide our own implementation of a fallback error handler. The basic idea is to wrap all JavaScript entry points with a try/catch block and call a predefined error handler on all exceptions. An entry point is a function, which is called directly by the browser. DOM event handlers or callbacks passed to window.setTimeout or window.setInterval are such entry points:

qx.event.GlobalError.setErrorHandler(function(ex) {
  console.log(ex);
});
 
window.setTimeout(qx.event.GlobalError.observeMethod(function() {
  throw new Error("Error");
}), 100);

globalerror_firebug

This time the error handler receives the real exception instance and not just the error message. qooxdoo already abstracts most of this low level event handling code so users won’t have to bother with wrapping their own methods (e.g. when using qx.Timer instead of a native window.setTimeout). For example all qooxdoo event handlers are already wrapped.

The implementation of observeMethod is a variation of a technique first documented by Nicholas Zakas:

observeMethod : function(method)
{
  if (qx.core.Setting.get("qx.globalErrorHandling") === "on")
  {
    var self = this;
    return function()
    {
      if (!self.__callback) {
        return method.apply(this, arguments);
      }
 
      try {
        return method.apply(this, arguments);
      } catch(ex) {
        self.__callback.call(self.__context, ex);
      }
    };
  }
  else
  {
    return method;
  }
}

The wrapped method is only enclosed by a try/catch block if an error handler is defined and the setting qx.globalErrorHandling is enabled. This is an important detail because the try/catch block can mess up the stacktrace and thus make the code harder to debug. In these cases the “normal” behavior can be restored by simply setting the error handler to null.

The global error handling is a replacement of the dysfunctional window.onerror and will be part of the next qooxdoo 0.8.3 release.

6 thoughts on “Global Error Handling

  1. Pingback: qooxdoo » News » This week in qooxdoo (2009-06-19)

  2. Pingback: Ajaxian » Qooxdoo 0.8.3; New widgets, layouts, and utilities

  3. Pingback: qooxdoo 0.8.3发布:构建RIA的好工具 « JobWp

  4. Pingback: qooxdoo 0.8.3发布:构建RIA的好工具 « en

  5. Pingback: qooxdoo » News » qooxdoo 0.8.3 released