In our applications, most of us hopefully follow the UX best practice of catching unexpected and/or unpreventable errors and logging them back to the server-side for monitoring.
In isolated scopes, this can be achieved by setting up a try-catch block, which also allows you to inspect the pertinent Error
object itself:
try {
throw new Error("WTF");
} catch (e) {
alert("Isolated error! Details: " + e);
}
This is very useful, especially in browsers that support the stack
property of the Error
object to improve "debugability". This property's availability is also of great benefit to @eriwen's StackTrace.js, which I find to be handy (though I'm not a big fan of the StrackTrace.js API, as @eriwen and I have discussed previously).
Setting up layers of try-catch blocks quickly becomes unreasonable in large applications. As an alternative, we can attach a listener to the window
object's error
event, which is invoked whenever an error bubbles up without being handled elsewhere:
var oldOnError = window.onerror;
window.onerror = function myErrorHandler(errorMsg, url, lineNumber) {
if (oldOnError) {
return oldOnError(errorMsg, url, lineNumber);
}
alert("Globally unhandled error! Details: " + errorMsg);
return false;
}
The problem is that this mechanism does not allow us to inspect the pertinent Error
object at all: it only provides us with three arguments at invocation time: message (string), fileName (string), and lineNumber (number). These are rarely useful in practice.
As such, I propose the following two options as fixes:
- Add a function like
getLastError
to the globalwindow
object that would fetch the actualError
object associated with the most recent unhandled error. I would foresee common usage looking something like the following:
var oldOnError = window.onerror;
window.onerror = function myErrorHandler(errorMsg, url, lineNumber) {
if (oldOnError) {
return oldOnError(errorMsg, url, lineNumber);
}
var e = window.getLastError();
alert("Globally unhandled error! But we now can discover its origin. Details: " + e);
return false;
}
- Alternatively (though less preferably), we could also update the invocation arguments of
window.onerror
callbacks to include a new fourth argument that would be the relevantError
object itself:
While this essentially makes the first three arguments useless, I have posed it this way for the sake of backward compatibility.var oldOnError = window.onerror; window.onerror = function myErrorHandler(errorMsg, url, lineNumber, e) { if (oldOnError) { return oldOnError(errorMsg, url, lineNumber, e); } alert("Globally unhandled error! But we now can discover its origin. Details: " + e); return false; }
When [synchronously] handling an Error
in an isolated scope, the active Error
object should be equivalent to the result of the window.getLastError()
function invocation:
try {
throw new Error("WTF");
} catch (e) {
assert(e === window.getLastError()); // true
}
I know I can't be alone here, especially since there are logged bugs for this in many trackers. For example: Mozilla's bug #355430 and StackTrace.js's Issues #26 and #9.
So... thoughts?
You forgot
this === e
inside theonerror
callback. Which I believe is what IE does currently.I think the notion that the
target
of the event is the error makes sense.