Dojo - 吞下promise的ReferenceError异常

时间:2013-06-25 23:03:31

标签: exception dojo promise deferred

在jQuery中,如果你在ajax回调方法中出错,你将得到一个正确的控制台错误信息和stacktrace。

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

然而,在使用dojo / request / xhr的dojo中,似乎这些愚蠢的错误正在被完全吞噬。我运行它时控制台中唯一的东西是“然后”和“总是”。

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');
    });
});

使用已弃用的dojo.xhrGet,问题略有改善。我收到一个控制台错误消息,我的错误处理程序被调用,但它只是说“ReferenceError {}”并为我提供了一个永远不会指向我拥有的函数的堆栈跟踪:

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');
    }
});

编写程序时,我们会犯错误,很高兴我们有像Chrome开发人员工具这样的工具来指出我们的错误。当您可以看到堆栈跟踪和错误消息时,找到错误所需的时间显然比没有反馈时快得多。我在dojo中没有得到任何反馈,我无法相信这样一个受欢迎的库可以以这种方式运行。我做错了什么?

3 个答案:

答案 0 :(得分:4)

在dojoConfig中设置useDeferredInstrumentation:true。这是an example

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

这在console.error上提供了一个相当实用的错误消息和stacktrace输出:

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" 

答案 1 :(得分:4)

你从jQuery继承的promises的理解与其他人(检查Promises / a + implementation)有着根本的不同。对于本答复的其余部分,我将讨论承诺/符合承诺的承诺。 Dojo的Deferred实际上不是+兼容的,但它足够接近我在这里讨论的所有内容同样适用。

Promise是不可变的,你不能通过调用then来改变promises状态。承诺代表了最终的价值,能够通过说“一旦价值准备好,做到这一点”来改变承诺是没有意义的。

那么,希望这能解释为什么不调用你的错误处理程序,但是捕获错误的基本思想仍然是完全可能的。您只需要使用返回值。当您在承诺上调用then时,它会返回一个新的(几乎总是)不同的承诺。这个新的承诺非常特殊,如果解析了原始版本,并且调用了你传递的成功处理程序,并返回了一些内容,那就是第二个promise的解析值。

同样,如果触发了错误处理程序(在第一个promise上),并且该函数返回了某些内容,则该内容将成为第二个promise的解析值。对于抛出的错误也是如此,它们被传递给错误处理程序(第二个承诺!)。

所以这是你的第一个以更多承诺/ a +方式编写的代码示例:

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');
    });
});

我真的不明白你想要用always函数做什么,所以我不知道在哪里放置那个。关于调用堆栈的主题,我建议检查具有令人难以置信的高级异步调用堆栈支持的Q promise库。

答案 2 :(得分:0)

我有非常具体的需求,因为我需要异常来点击浏览器实现的本地catch子句。没关系为什么我需要这个,但是我使用了这样的东西:

function scream(func) {
    return function() {
        var args = arguments;
        setTimeout(function(){
            func.apply(null, args);
        }, 0);
    };
}

然后,使用它

var promise = xhr.get("https://api.github.com/users/octocat/orgs");
promise.then(scream(function(data) {
    //do stuff
}));

通过使用setTimeout,您可以在browsers事件队列中执行该函数,从而使dojo无法吞下您的异常。但是,一般来说这是一个糟糕的解决方案,因为:

  • 它会改变堆栈跟踪的一部分
  • 它会将以前同步执行的代码的一部分更改为异步,这可能会改变程序行为
  • 你不能将多个.then()promise对象链接到返回值,这是关于promises的一个非常好的事情。

无论如何,我只是将它作为选项提出。