Exception Dojo-承诺中的ReferenceError异常被吞并

Exception Dojo-承诺中的ReferenceError异常被吞并,exception,dojo,promise,deferred,Exception,Dojo,Promise,Deferred,在jQuery中,如果您在ajax回调方法中出错,您将得到一条正确的控制台错误消息和stacktrace $.get("https://api.github.com/users/octocat/orgs", function() { var a = FAIL; }); 然而,在使用dojo/request/xhr的dojo中,这些愚蠢的错误似乎被完全吞没了。运行此命令时,控制台中唯一的内容是“然后”和“始终” 使用不推荐使用的dojo.xhrGet,问题得到了非常轻微的改进。我收到一条控制

在jQuery中,如果您在ajax回调方法中出错,您将得到一条正确的控制台错误消息和stacktrace

$.get("https://api.github.com/users/octocat/orgs", function() {
  var a = FAIL;
});
然而,在使用dojo/request/xhr的dojo中,这些愚蠢的错误似乎被完全吞没了。运行此命令时,控制台中唯一的内容是“然后”和“始终”

使用不推荐使用的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 developer之类的工具来指出这些错误。当您可以看到stacktrace和错误消息时,查找错误所需的时间显然比您没有收到反馈时要快得多。我在dojo中没有得到任何反馈,我不敢相信如此受欢迎的库能够以这种方式运行。我做错了什么?

在dojoConfig集合中,UseDeferedInstrumentation:true。给你


对从jQuery继承的承诺的理解与其他人(检查承诺/a+实现)的理解有根本的不同。对于这个答案的其余部分,我将讨论承诺/a+合规承诺。Dojo's Deferred实际上并不是一个+兼容的程序,但它非常接近,我在这里讨论的所有内容都同样适用

承诺是不可变的,您不能通过调用
然后
来更改承诺状态。承诺代表最终的价值,如果能够通过说“一旦价值准备好了,就这么做”来改变承诺,那将是荒谬的

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

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

下面是您的第一个代码示例,它是以更具承诺/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库,该库具有难以置信的高级异步调用堆栈支持。

我有非常特殊的需求,因为我需要异常来命中浏览器实现的本机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()promise对象链接到返回值,这是promises的一个非常好的特性

无论如何,我只是把它作为一个选项来介绍。

当然,能够在window.onerror之类的东西中捕捉或处理这些错误会很好。有什么建议吗?这是一个很好的解释。这里对您的代码做了一个小小的修改,它也提供了stacktrace:不幸的是,stack trace没有指向正确的行(它指向console.error行)。因此,如果你想抓住错误,这是正确的答案;如果你想找出错误,我倾向于选择我的答案。然而,如果您确实捕获了错误,那么插装将被抑制,因此您无法同时获得这两个方面的最佳效果。您是对的,它更像是一个消息传递服务(“存在错误”),而不是带有堆栈跟踪的完整错误抛出服务。我强烈建议您查看Q库,它是我所知道的最好的异步库,它们肯定会处理这个问题。
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');
    });
});
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
}));