5

在 jQuery 中,如果您在 ajax 回调方法中出错,您将收到正确的控制台错误消息和堆栈跟踪。

$.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 开发者工具这样的工具来指出这些错误。当您可以看到堆栈跟踪和错误消息时,发现错误所需的时间显然比没有收到反馈要快得多。我在道场没有得到任何反馈,我不敢相信这样一个受欢迎的图书馆可以这样运作。我究竟做错了什么?

4

3 回答 3

4

在 dojoConfig 中设置 useDeferredInstrumentation: true。这是一个例子

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

这会在 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" 
于 2013-06-25T23:26:53.143 回答
4

对从 jQuery 继承的 Promise 的理解与其他人(检查 Promises/a+ 实现)的理解完全不同。对于这个答案的其余部分,我将讨论 promises/a+ 兼容的 promises。Dojo 的 Deferred 实际上不符合 a+ 标准,但它足够接近,以至于我在这里讨论的所有内容都同样适用。

Promise 是不可变的,你不能通过调用来改变 Promise 状态then。一个承诺代表一个最终的价值,如果能够通过说“一旦价值准备好,就这样做”来改变承诺是荒谬的。

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

同样,如果错误处理程序(在第一个 promise 上)被触发,并且该函数返回一些东西,那么这个东西将是第二个 promise 的分辨率值。抛出的错误也是如此,它们被传递给错误处理程序(第二个承诺!)。

所以这是你的第一个代码示例,它以更多的 promises/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 库,它具有非常先进的异步调用堆栈支持。

于 2013-06-27T13:27:03.560 回答
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,您可以在浏览器事件队列上执行该函数,从而使 dojo 无法吞下您的异常。但是,总的来说,这是一个糟糕的解决方案,因为:

  • 它改变了堆栈跟踪的一部分
  • 它将以前同步执行的部分代码更改为异步执行,这可以改变程序行为
  • 您不能将多个 .then() 承诺对象链接到返回值,这是关于承诺的真正好处之一。

无论如何,我只是将其作为选项呈现。

于 2014-01-21T16:25:18.420 回答