简体   繁体   中英

How do I debug my asynchronous, promise based code if the library is swallowing all the exceptions?

The Problem

JSFiddle : http://jsfiddle.net/missingno/Gz8Pe/2/

I have some code that looks like this:

var d = new Deferred();
d.resolve(17);
return d.then(function(){
     //do some stuff...
})
.then(function(){
    var obj = a_funtion_that_returns_null_on_IE();
    var x = obj.some_property; //BOOM!
});

The problem is that when I am on IE all I can see are 'obj' is null or not an object errors, without any reference to the corresponding line number and without the debugger halting at the offending line (like I wish it would).

This kind of issue is making the code a pain to debug and the only solutions I can think of right now (messing around with the control flow library or resorting to step-by-step debugging with the debugger or console.log) are things I would rather not have to do.

What I think is going on

In order to allow errbacks to be added after the chain is fired, then will preemptively catch any exceptions thrown by the callbacks. I think this is the reason for the IE debugger not halting on the error or showing the usual error message witht the line number in it.

The error messages without the line numbers are coming from the control-flow library: it provides a deferredOnError hook that is called whenever an exception is caught and saved for later and the default behaviour is console.error-ing the Error object:

dojo.config.deferredOnError = function(err){
    //a chance to log the exception after it is captured by "then"
    //or do other things with it
    console.error(err);
}

Sadly, I could not figure out a way to get the line number or stack trace from the error object in IE and the hook is called in a way that does not allow me to just rethrow the exception and let it bubble up to the toplevel.

What I want

I want to have a better way to debug the async code then goind along with the debugger step-by-step. In the best case a way to have the debugger halt on the exceptions (as it does on unhandled exceptions) or at least a way to get line numbers or stack traces from the Error object that was thrown.

This works with any framework without prior configuration and all recent browsers support this.

Pause On Caught Exceptions: This will actually stop javascript's execution and will take you exactly where the problematic code is, as it's happening.

暂停捕获的异常

In Chrome:

  1. Developer Tools ,
  2. Sources tab,
  3. Pause on exceptions (stop-like icon) and then
  4. the Pause On Caught Exceptions checkbox

What I ended up doing

I added a sequencing function to my mini library of async helper functions. It basically runs a sequence of "then" calls, except that it adds extra intermediate steps to rethrow any exceptions that end up being caught by the Deferreds. It also accepts an optional error handler to catch the exceptions.

When I call it it looks like this:

go([
    function(){
        return 17;
    },
    function(x){
        //return some stuff
    },
    function(){
         var obj = a_function_that_returns_null_on_IE();
         var x = obj.some_property; //BOOM!
    }
], function(){
    //an optional error handler
});

Another reason that I did things this way is that I have lots of code that needs to work simultaneously with either sync or async code (using Deferred.when to do the chaining). Using my custom function let me use a single, unified syntax and the errors not being captured in the async case is consistent with the sync case, where there are no Deferreds involved. I also think its OK to not capture the error, since unlike in the general case, when I am using "go" I know a-priori what code will be called, so there is no need to capture exceptions for if someone needs to catch them in the future.

Also, using a custom solution gave me the freedom to enforce some personal design preferences :)


In addition to that, I ended up reducing the amount of exceptions I generate myself throughout the code base. Managing exceptions in async code is more annoying then usual and sometimes its simpler to just fallback into handling error conditions by returning null or an error code.

Also, we made sure that any exceptions that we create ourselves are instances of the builtin Error class, intead of other objects. The reason is that the builtin Error class records the line number and stack trace of where it was generated in a kind of cross-browser way.

2016 solution

If you're using native ES Promises do absolutely nothing; Chrome automatically reports uncaught promise rejections in the console.

Chrome开发工具中的“Uncaught Promise错误”

Notice how the caught one ( Second fail ) doesn't show anything but the uncaught rejection appears in the console after the code is done running.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM