Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

silent javascript errors

This may be a bad question, but I've noticed that as I'm writing coding along using mootools When I've got some code that goes through callbacks, bindings and generally isn't just a straight forward function call, if there's an error it doesn't get picked up by either Firebug or Chrome's console it just silently fails, and I'm forced to track down the error using trys and such that don't give you handy information like the line of code that's failing. It's like writing code for IE6 all you have to go on is some opaque message like 'can not read 'x' of undefined.'

I realize that the question isn't specific enough to ask 'how do I avoid this' but does anyone else run into this problem and if so how do you work around it? I'm also a little confused how an error could be picked up by a try/catch block, but not the javascript console.

EDIT:

OK, I've come up with something that reproduces the error

say you've got a function

function foo(){
   var x = value.blah;
}

if I call that function like foo() I rightly get an reference error in my console. If, however, I call it like

(function(){
   foo.attempt();
})()

I get no error in the console, but if I change foo to be

function foo(){
   try{
   var x = value.blah;
   } catch(e){console.log(e)}
}

the console will log e but of course without the handle 'line: whatever' information.

like image 228
hobberwickey Avatar asked Nov 16 '12 21:11

hobberwickey


People also ask

What is a silent error?

Silent errors are errors in application state that have escaped low-level error detection. At extreme scale, where machines can perform astronomically many operations per second, silent errors threaten the validity of computed results. We propose a new paradigm for detecting silent errors at the application level.


1 Answers

I have considerable experience fiddling with errors in JavaScript. I've mostly used Chrome for building my understanding but most of it applies to Firefox and Internet Explorer as well.

I can immediately debunk your assumption about silent JavaScript errors. They don't exist, Errors always show. There might be a bug in Firefox or the Chrome's webdev, but the errors are there.

The most common way for errors not to show up is because you're catching them yourself. Perhaps prematurely.

I've figured out what I think is the best strategy for catching errors:

1. Always throw things that are Errors or inherited from Errors.

Ex: not: throw "Precondition failed" but throw new Error("Precondition failed").

This is because Errors are weird in JavaScript (I have no other word for it). If you want a stacktrace (and heaven's yes you want a stacktrace) you'll need to throw an Error (and not a string).

2. Don't use window.onerror Not much to say here. It's useless. You have no control over what get's flung to this function. It might be your code, it might be a broken plugin that a visitor uses. Also, no stacktrace.

3. Have one (global) error handler / when to catch errors

JavaScript is event driven. This has some unexpected consequences. Observe the following code:

try {
    setTimeout(function () {
        throw new Error("nope! :D");
    }, 1);
} catch (e) {
    console.log(e);
}

You will not see this error. (Firebug / console will catch it though)

This is because the inner function runs in it's own event and the try-catch statement no longer applies to it. The correct way is:

try {
    setTimeout(function () {
        try {
            throw new Error("nope! :D");
        } catch (e) {
            console.log("Hell yea!", e);
        }
    }, 1);
} catch (e) {
    console.log(e);
}

Or just make a function that wraps a function in a try-catch:

function wrap(wrap_dat_func) {
    return function () {
        try {
            wrap_dat_func.apply(wrap_dat_func, arguments);
        } catch (e) {
            // send to error handler
        }
   }
}

Use like:

setTimeout(wrap(function () {
    // etc
}), 1);

So basically whenever you generate a new event, wrap the callback in your global try catch function. So wrap call to setTimeout, setInterval all DOM related events like onclick onload ondocumentready, also AJAX calls onreadystatechanged.

How to get proper stacktraces (over events!) is another long winded explanation.

like image 85
Halcyon Avatar answered Oct 20 '22 12:10

Halcyon