0

I want to log all errors in my browser side JavaScript code. I saw a lot of discussions here and on the net about window.onerror and it is clear it does not work cross browser. So, I plan to wrap top level entry functions with try - catch. Trouble is, a lot of my code is event handlers. I have not tested it yet, but I am pretty sure that no matter where the event handler function is defined, a thrown error will fire out directly to the browser implementation that calls it, not to event function declaring code. My only choice is to declare throw, catch and error log calls in every error handler even the tiniest anonymous one. I don't like that one bit.

A possible solution:

I use one method to cross browser register events. I can modify it to do something like this:

function registerEventHandler(object, handlerRef) {
  var wrapperFunction = function(evt) {
  try {        
    handlerRef(evt);
  } catch {
    logError(error);
  }
  registerEvent(object, wrapperFunction);
}

There is one major problem with that implementation. I often keep references to event handler function in order to deregister them later. This will not work as the function registered as the handler will be the wrapper, not the original one. The answer to this is to implement a wrapper -> wrapped mapping object and use it on unregister.

The question:

I dare you JavaScript magicians to come up with more clever solution than that. Maybe it could be done by somehow augmenting the event handler function before registration? This is a far as my JavaScript knowledge goes. What about yours?

Boris Hamanov
  • 2,884
  • 9
  • 31
  • 57

1 Answers1

1

I often keep references to event handler function in order to deregister them later. This will not work as the function registered as the handler will be the wrapper, not the original one.

Why is this a problem? once the function is wrapped in the error handling, you dont really care about the original function anymore. The wrapper keeps a reference to your original function, and the wrapper is what is registered, and the wrapper is what needs to be unregistered.

Just keep a reference to your wrapper function you generate because its the only one that matters.


Also making it it's own function will make this pattern far more reusable

var protectErrors = function(fn) {
  var that = this;
  return function() {
    try {
      fn.apply(that, arguments);
    } catch(error) {
      logError(error);
    }
  };
};

var registerEventHandler = function(object, handlerRef) {
  var wrapperFunction = protectErrors(handlerRef);
  registerEvent(object, wrapperFunction);
};

protectErrors(fn) will return a function that runs the original in whatever context it was called in, and forwarding any number of arguments.

Alex Wayne
  • 145,435
  • 42
  • 271
  • 302
  • It is not much of a problem Squeegy, it is just more overhead. I don't want it I can help it. – Boris Hamanov Feb 10 '11 at 08:43
  • (Minor update to make `protectErrors` more generalized, btw). Well as far as overhead if you cant use global error handling, the only other choice is local try catches. not really a way around that. – Alex Wayne Feb 10 '11 at 08:52
  • why do you assign this to that, before calling apply? – Boris Hamanov Feb 10 '11 at 15:59
  • Because the inner function loses it's connection to `this`. Assigning `this` local variable outside the inner function allows it to stick around. http://stackoverflow.com/questions/4886632/what-does-var-that-this-mean-in-javascript – Alex Wayne Feb 10 '11 at 16:08