Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Dojo - ReferenceError exception in promise being swallowed

In jQuery, if you make a mistake in your ajax callback method, you will get a proper console error message and stacktrace.

$.get("https://api.github.com/users/octocat/orgs", function() {
  var a = FAIL;
});

However, in dojo using dojo/request/xhr it seems these dumb mistakes are being swallowed completely. The only thing in my console when I run this is "then" and "always".

require(["dojo/request/xhr" ], function(xhr) {
    var promise = xhr.get("https://api.github.com/users/octocat/orgs");
    promise.then(function(data) {
        console.log('then');
        var a = FAIL;
        console.log('goodbye');
    }, function() {
        console.log('error');
    });
    promise.otherwise(function() {
        console.log('otherwise');
    });
    promise.always(function() {
        console.log('always');
    });
});

Using the deprecated dojo.xhrGet, the problem is very slightly improved. I get a console error message and my error handler is called but it only says "ReferenceError {}" and provides me with a stack trace that never points to a function I own:

dojo.xhrGet({
    url: "https://api.github.com/users/octocat/orgs",
    load: function() {
        console.log('dojo.xhrGet.load');
        var a = FAIL;

        console.log('goodbye dojo.xhrGet.load');
    },
    error: function() {
        console.log('dojo.xhrGet.error');
    },
    handle: function() {
        console.log('dojo.xhrGet.handle');
    }
});

When writing a program we make mistakes, it's nice that we have tools like chrome developer tools to point us to those mistakes. The time it takes to find an error when you can see a stacktrace and error message is obviously much quicker than if you get no feedback. I get no feedback in dojo, I can't believe that such a popular library could operate in this way. What am I doing wrong?

like image 812
case nelson Avatar asked Jun 25 '13 23:06

case nelson


People also ask

How does a promise catch an exception in JavaScript?

Normally, such .catch doesn’t trigger at all. But if any of the promises above rejects (a network problem or invalid json or whatever), then it would catch it. The code of a promise executor and promise handlers has an "invisible try..catch " around it. If an exception happens, it gets caught and treated as a rejection.

What happens when a promise is rejected?

But if any of the promises above rejects (a network problem or invalid json or whatever), then it would catch it. The code of a promise executor and promise handlers has an "invisible try..catch " around it. If an exception happens, it gets caught and treated as a rejection.

Are swallowed exceptions a thing of the past?

Let’s make swallowed exceptions a thing of the past. No more empty catch blocks, and no more unknown errors. Does the scenario we described sounds familiar? Did you have other experiences with swallowed exceptions? Let us know in the comments section below! Alex is the Director of Product Marketing at OverOps.

How do you handle errors in promises?

Error handling with promises 1 Implicit try…catch. The code of a promise executor and promise handlers has an "invisible try..catch " around it. ... 2 Rethrowing. As we already noticed, .catch at the end of the chain is similar to try..catch. ... 3 Unhandled rejections. What happens when an error is not handled? ... 4 Summary. ...


2 Answers

The understanding of promises which you inherited from jQuery is fundamentally different to the one everyone else (check Promises/a+ implementations) has. For the rest of this answer I will talk about promises/a+ compliant promises. Dojo's Deferred actually isn't a+ compliant, but it's close enough that everything I discuss here applies equally well.

Promises are immutable, you cannot change a promises state by calling then. A promise represents an eventual value, it would be nonsensical to be able to change the promise by saying "once the value is ready, do this".

So then, hopefully that explains why your error handler is not invoked, but the basic idea, of catching errors, is still totally possible. You just need to use return values. When you call then on a promise, it returns a new and (almost always) different promise. This new promise is very special, if the original is resolved, and the success handler you passed is invoked, and that returns something, that something will be the resolution value of the second promise.

Equally, if the error handler (on the first promise) is triggered, and that function returns something, that something will be the resolution value of the second promise. The same is true for thrown errors, they are passed to the error handler (of the second promise!).

So here's your first code sample written in a more promises/a+ way :

require(["dojo/request/xhr" ], function(xhr) {
    var promise = xhr.get("https://api.github.com/users/octocat/orgs");
    promise.then(function(data) {
        console.log('then');
        var a = FAIL;
        console.log('goodbye');
    }, function() {
        console.log('error');
    }).then(null, function() {
        console.log('otherwise');
    });

    promise.always(function() {
        console.log('always');
    });
});

I don't really understand what you want to do with the always function, so I wasn't sure where to place that one. On the subject of call stacks, I would recommend checking out the Q promise library which has incredibly advanced asynchronous call stack support.

like image 157
Frances McMullin Avatar answered Oct 22 '22 02:10

Frances McMullin


In dojoConfig set useDeferredInstrumentation: true. Here's an example.

        <script>
           var dojoConfig = {
                useDeferredInstrumentation: true
            };
        </script>
        <script src="js/lib/dojo/dojo.js.uncompressed.js"></script>

This gives a fairly functional error message and stacktrace output on console.error:

ReferenceError {} "ReferenceError: FAIL is not defined
    at http://fiddle.jshell.net/gNdCb/2/show/:25:17
    at signalListener (http://ajax.googleapis.com/ajax/libs/dojo/1.9.0/dojo/dojo.js.uncompressed.js:14205:21)
    at signalWaiting (http://ajax.googleapis.com/ajax/libs/dojo/1.9.0/dojo/dojo.js.uncompressed.js:14196:4)
    at resolve (http://ajax.googleapis.com/ajax/libs/dojo/1.9.0/dojo/dojo.js.uncompressed.js:14360:5)
    at signalDeferred (http://ajax.googleapis.com/ajax/libs/dojo/1.9.0/dojo/dojo.js.uncompressed.js:14249:15)
    at signalListener (http://ajax.googleapis.com/ajax/libs/dojo/1.9.0/dojo/dojo.js.uncompressed.js:14220:6)
    at signalWaiting (http://ajax.googleapis.com/ajax/libs/dojo/1.9.0/dojo/dojo.js.uncompressed.js:14196:4)
    at resolve (http://ajax.googleapis.com/ajax/libs/dojo/1.9.0/dojo/dojo.js.uncompressed.js:14360:5)
    at signalDeferred (http://ajax.googleapis.com/ajax/libs/dojo/1.9.0/dojo/dojo.js.uncompressed.js:14249:15)
    at signalListener (http://ajax.googleapis.com/ajax/libs/dojo/1.9.0/dojo/dojo.js.uncompressed.js:14226:4)
    ----------------------------------------
    rejected at signalDeferred (http://ajax.googleapis.com/ajax/libs/dojo/1.9.0/dojo/dojo.js.uncompressed.js:14252:15)
    at signalListener (http://ajax.googleapis.com/ajax/libs/dojo/1.9.0/dojo/dojo.js.uncompressed.js:14223:5)
    at signalWaiting (http://ajax.googleapis.com/ajax/libs/dojo/1.9.0/dojo/dojo.js.uncompressed.js:14196:4)
    at resolve (http://ajax.googleapis.com/ajax/libs/dojo/1.9.0/dojo/dojo.js.uncompressed.js:14360:5)
    at signalDeferred (http://ajax.googleapis.com/ajax/libs/dojo/1.9.0/dojo/dojo.js.uncompressed.js:14249:15)
    at signalListener (http://ajax.googleapis.com/ajax/libs/dojo/1.9.0/dojo/dojo.js.uncompressed.js:14220:6)
    at signalWaiting (http://ajax.googleapis.com/ajax/libs/dojo/1.9.0/dojo/dojo.js.uncompressed.js:14196:4)
    at resolve (http://ajax.googleapis.com/ajax/libs/dojo/1.9.0/dojo/dojo.js.uncompressed.js:14360:5)
    at signalDeferred (http://ajax.googleapis.com/ajax/libs/dojo/1.9.0/dojo/dojo.js.uncompressed.js:14249:15)
    at signalListener (http://ajax.googleapis.com/ajax/libs/dojo/1.9.0/dojo/dojo.js.uncompressed.js:14226:4)
    ----------------------------------------
Error
    at Promise.then.promise.then (http://ajax.googleapis.com/ajax/libs/dojo/1.9.0/dojo/dojo.js.uncompressed.js:14420:24)
    at http://fiddle.jshell.net/gNdCb/2/show/:23:13
    at runFactory (http://ajax.googleapis.com/ajax/libs/dojo/1.9.0/dojo/dojo.js.uncompressed.js:1117:43)
    at execModule (http://ajax.googleapis.com/ajax/libs/dojo/1.9.0/dojo/dojo.js.uncompressed.js:1245:5)
    at http://ajax.googleapis.com/ajax/libs/dojo/1.9.0/dojo/dojo.js.uncompressed.js:812:7
    at guardCheckComplete (http://ajax.googleapis.com/ajax/libs/dojo/1.9.0/dojo/dojo.js.uncompressed.js:1260:5)
    at contextRequire (http://ajax.googleapis.com/ajax/libs/dojo/1.9.0/dojo/dojo.js.uncompressed.js:811:6)
    at req (http://ajax.googleapis.com/ajax/libs/dojo/1.9.0/dojo/dojo.js.uncompressed.js:137:11)
    at http://fiddle.jshell.net/gNdCb/2/show/:21:1" 
like image 42
case nelson Avatar answered Oct 22 '22 01:10

case nelson