从JS

时间:2015-08-12 10:31:58

标签: javascript jquery deferred

我正在使用本机承诺(主要是)并尝试从错误中恢复并继续执行承诺链。

有效地,我这样做:

  • REST查询以查看ID是否存在。 请注意,这将返回延迟的jquery。
  • .then(成功意味着ID存在,所以失败并停止)     (fail表示ID不存在,因此请继续创建ID)
  • .then(创建ID记录并发送到服务器)

我从被拒绝的函数返回一个Promise.resolve(),它应该导致下一个.then的成功部分执行。它不是。我在Chrome和Safari上试过这个。

请注意,第一个promise实际上是一个延迟的查询,但根据此页面(http://api.jquery.com/deferred.then/),deferred.then()返回一个promise对象。因此,添加额外的.then应该转换为原生承诺。

为了更清楚 - 这是伪代码:

promise = $.ajax(url);
promise = promise.then();  // convert to promise 
promise.then(function() { cleanup(); return Promise.reject(); },
    function(err) { return Promise.resolve(); });
.then(function() { createIdentityDetails(); });
.then(function() { sendIdentityDetails(); });

请注意,当ajax返回成功时我想要失败,我想 当ajax调用失败时继续处理。

发生的是所有后续部分的FAIL功能执行。也就是说,我的返回Promise.resolve()不起作用 - 这是(我认为)违反规范。

我很感激有关如何处理长期承诺链中的错误并从中恢复的任何反馈。

非常感谢您提供的任何建议。

P.S。创建和收集完整的身份信息非常耗时,因此如果ID存在,我不想这样做。因此,我想先检查并快速失败。

p.p.s我真的很喜欢promises解开这些深度嵌套的异步回调链的方式。

4 个答案:

答案 0 :(得分:1)

似乎JQuery承诺不允许您将失败转变为成功。但是,如果您使用原生承诺,则可以。

例如:

Promise.resolve()
    .then(function() {console.log("First success"); return Promise.reject(); },
        function() { console.log("First fail"); return Promise.resolve(); })
    .then(function() {console.log("Second success"); return Promise.reject(); },
        function() { console.log("Second fail"); return Promise.resolve(); })
    .then(function() {console.log("Third success"); return Promise.reject(); },
        function() { console.log("Third fail"); return Promise.resolve(); })

这里我从第一个成功处理程序返回拒绝。在第二个失败处理程序中,我返回一个决心。这一切都按预期工作。输出是(Chrome):

First success
Second fail
Third success

事实证明正确的方式来处理jQuery延迟,并且承诺是投射它们:

var jsPromise = Promise.resolve($.ajax('/whatever.json'));

(来自http://www.html5rocks.com/en/tutorials/es6/promises/)。 这很好用,所以如果你将上面的初始行更改为:

Promise.resolve($.ajax("this will fail"))
...

你正确得到:

First fail
Second success
Third fail

底线...演员推迟承诺,然后一切似乎都正常。

答案 1 :(得分:1)

promise = promise.then();  // convert to promise

咦? $.ajax返回的承诺已经是一个承诺。

promise.then(function() { cleanup(); return Promise.reject(); },
 function(err) { return Promise.resolve(); });

这个问题是jQuery不是Promises/A+兼容的,并且无法从其他实现中采用promises / thenable而不是它自己的。你需要use $.Deferred here来完成这项工作,比如

promise.then(function() { cleanup(); return $.Deferred().reject(); },
             function() { return $.when(); }); // or return $.Deferred().resolve();
  

也就是说,我的return Promise.resolve()不起作用 - 这是(我认为)违反规范。

确实如此。但是,jQuery is known for this,他们将不会修复它直到v3.0。

要获得要使用的本地Promise库,您需要避免使用jQuery的then。这can easily be done

var $promise = $.ajax(url);
var promise = Promise.resolve($promise);  // convert to proper promise 
promise.then(function() {
    cleanup();
    throw undefined;
}, function(err) {
    return undefined;
})
.then(createIdentityDetails)
.then(sendIdentityDetails);

答案 2 :(得分:1)

假设createIdentityDetails()sendIdentityDetails()是承诺 - 返回异步函数......

如果我们在问题中看到的是整个承诺链,那么处理错误条件很简单。没有必要将成功转化为失败或失败转为成功,或从一种承诺转变为另一种承诺。

$.ajax(url).then(function() {
    cleanup();
}, function(err) {
    createIdentityDetails()
    .then(sendIdentityDetails);
});

无论createIdentityDetails() jQuery或非jQuery返回的承诺类型如何,这都可以。

但是,如果还有更多内容,例如呼叫者功能需要被告知结果,那么您需要做更多,这取决于您希望如何报告可能的结果。 / p>

报告' ID已存在'因为失败并且创建了新的ID'成功

这就是问题所暗示的

function foo() {
    return $.ajax(url).then(function() {
        cleanup();
        return $.Deferred().reject('failure: ID already exists');
    }, function(err) {
        return createIdentityDetails()
        .then(sendIdentityDetails)
        .then(function() {
            return $.when('success: new ID created');
        });
    });
}

将两种类型的结果报告为成功

这似乎更明智,因为处理错误将被报告为成功。只会报告不可预测的未处理错误。

function foo() {
    return $.ajax(url).then(function() {
        cleanup();
        return 'success: ID already exists';
    }, function(err) {
        return createIdentityDetails()
        .then(sendIdentityDetails)
        .then(function() {
            return $.when('success: new ID created');
        });
    });
}

无论采用哪种报告策略,重要的是什么类型的承诺createIdentityDetails()都会返回。作为链中的第一个承诺,它决定了它的链式.thens的行为。

  • 如果createIdentityDetails()返回本机ES6承诺,那么不用担心,大多数风格的承诺,甚至是jQuery,都会被同化。
  • 如果createIdentityDetails()返回jQuery承诺,那么只有jQuery promises才会被同化。因此sendIdentityDetails()还必须返回一个jQuery承诺(或者必须使用$.Deferred(...)重新转换为jQuery的ES6承诺),最后的成功转换器(如上面编码的那样)必须返回。

您可以通过这两种方式here看到混合jQuery和ES6承诺的效果。第一个警报由第二个代码块生成,而不是预期的。第二个警报由第一个块生成,并正确地给出结果98 + 1 + 1 = 100。

答案 3 :(得分:0)

希望这会让事情变得清晰,你有几个流浪;并且你正在做你不需要做的事情

首先,我确定你不想要

promise = promise.then();

行,代码看起来像这样

promise = $.ajax(url);
promise.then(function() { 
    cleanup(); 
    throw 'success is an error'; // this is equivalent to return Promise.reject('success is an error');
}, function(err) { 
    return 'failure is good';  // returning here means you've nullified the rejection
}) // remove the ; you had on this line
.then(function() { createIdentityDetails(); }) // remove the ; on this line
.then(function() { sendIdentityDetails(); }) // remove the ; on this line
.catch(function(err) { }); // you want to catch the error thrown by success
相关问题