W3C home > Mailing lists > Public > whatwg@whatwg.org > May 2012

Re: [whatwg] Proposal: Add window.getLastError (or modify invocation arguments of window.onerror)

From: Simon Pieters <simonp@opera.com>
Date: Wed, 09 May 2012 11:12:26 +0200
To: whatwg@whatwg.org, "James Greene" <james.m.greene@gmail.com>
Message-ID: <op.wd1ai0n4idj3kv@simons-macbook-pro.local>
On Wed, 09 May 2012 03:56:29 +0200, James Greene  
<james.m.greene@gmail.com> wrote:

> Full proposal details:
>     https://gist.github.com/3ded0f6e7f0a658b9394

quoting the above (revision  
https://gist.github.com/3ded0f6e7f0a658b9394/51e980f0474c255738a3b6ecf003bb6cb30db49c  
):

> # Proposal: Add `window.getLastError` (or modify `window.onerror`)
>## Error handling in an isolated scope
> 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`][1]  
> 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`][2] property of the `Error` object to improve "debugability".   
> This property's availability is also of great benefit to @eriwen's  
> [StackTrace.js][3], 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).
>## Error handling at the global scope
> Setting up layers of try-catch blocks quickly becomes unreasonable in  
> large applications.  As an alternative, we can attach a listener  to the  
> [`window`][4] object's [`error`][5] event, which is invoked whenever an  
> error bubbles up without being handled elsewhere:

(It's not actually a real event.)

> ```
> 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 with `window.onerror`
> 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.

The spec now has a fourth argument for the column number (which is more  
useful than line number for minimized scripts). Maybe column could be made  
available on exceptions as well, though that's up to TC39, I think.  
('stack' isn't specified currently, IIRC.)

>## My proposal(s) to fix it
> As such, I propose the following two options as fixes:
>  1. Add a function like `getLastError` to the global `window` object  
> that would fetch the actual `Error` 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;
> }
> ```
>  2. 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 relevant `Error` object itself:
>     ```
>     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;
>     }
>     ```
>     While this essentially makes the first three arguments useless, I  
> have posed it this way for the sake of backward compatibility.

I'd prefer this second option (except making it the fifth argument),  
because the exception object can become garbage earlier and because for  
cross-origin script errors, the arguments to window.onerror are masked for  
security reasons, and we would need to mask the exception object as well,  
so it seems better to use the same mechanism for that.

Also for compile script errors, there is no exception object.

Are there other things on the exception object that are of interest, or  
just the stack? If it's just the stack, maybe we could dump that as a  
string argument?


> ## Errata
> 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
> }
> ```
>## Summary
> 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][6] and  
> StackTrace.js's Issues [#26][7] and [#9][8].
>So... thoughts?
>[1]:  
> https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Error
> [2]:  
> https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Error/Stack
> [3]: http://stacktracejs.com/
> [4]: https://developer.mozilla.org/en/DOM/window
> [5]: https://developer.mozilla.org/en/DOM/window.onerror
> [6]: https://bugzilla.mozilla.org/show_bug.cgi?id=355430
> [7]: https://github.com/eriwen/javascript-stacktrace/issues/26
> [8]: https://github.com/eriwen/javascript-stacktrace/issues/9

-- 
Simon Pieters
Opera Software
Received on Wednesday, 9 May 2012 09:14:23 GMT

This archive was generated by hypermail 2.2.0+W3C-0.50 : Wednesday, 30 January 2013 18:48:08 GMT