2

使用jQuery.when(),如果一个请求失败,那么它们都会失败。

$.when(deferred1, deferred2).then(function() {
    // Called only after both deferred are resolved
}, function() {
    // Called immediately after one of the deferreds is rejected
});

你怎么能等待一切都执行甚至失败?我尝试使用.always()而不是,.then()但在第一次失败后也立即调用了回调。

一个(丑陋的)解决方案是使用标志来控制两个操作何时完成并.always()在每个操作上使用 (不带$.when())。

var deferred1Complete = false;
var deferred2Complete = false;

function callback() {
    if (deferred1Complete && deferred2Complete) {
        // Execute after both deferred are either resolved or rejected
    }
}

deferred1.always(function() {
    deferred1Complete = true;
    callback();
});

deferred2.always(function() {
    deferred2Complete = true;
    callback();
});

有一个更好的方法吗?

4

2 回答 2

3

乔纳坦,

我喜欢您的解决方案,并提供了一些改进:

  • 短语作为 jQuery 实用方法,如$.when()
  • 允许传入单个 promise 或一组 promise
  • 如果没有传入参数或传入空数组,则立即解析
  • 容忍非承诺/非延迟
  • 允许在解决或拒绝每个承诺时报告链的进度。

这是代码:

(function($) {
    $.whenAlways = function(chain) {
        if(!chain || !$.isArray(chain)) chain = $.extend([], arguments);
        var n = chain.length;
        return $.Deferred(function(deferred) {
            $.each(chain, function(i, promise) {
                if(!promise.always) n--;
                else {
                    promise.always(function() {
                        deferred.notify(--n);
                        if(n == 0) deferred.resolve();
                    });
                }
            });
            if(n == 0) deferred.resolve();
        }).promise();
    }
})(jQuery);

这种方法将允许任何progressCallbacks(添加到重新调整的promise)在chainpromise 被reolved/rejected 时被调用,而不管reollution/rejection 顺序如何。例如,通过将未完成的chain承诺数量传递给 progressCallbacks,您可以提供倒计时指示或响应中间倒计时里程碑。

似乎工作 -演示

于 2013-03-09T12:33:03.273 回答
2

另一个解决方案(不是那么难看)是链接延迟.always()回调。

deferred1.always(function() {
    deferred2.always(function() {
        // Execute after both deferred are either resolved or rejected
    });
});

我写了一个小函数来处理这个:

function whenAlways() {
    var chain = $.extend([], arguments);
    return new $.Deferred(function(deferred) {
        var callback = function() {
            if (chain.length == 0) {
                deferred.resolve();
                return;
            }
            var object = chain.shift();
            $.when(object).always(callback);
        };
        callback();
    }).promise();
}

用法:

whenAlways(deferred1, deferred2)
    .done(function() {
        // Execute after both deferred are either resolved or rejected
    });
于 2013-03-09T04:21:19.943 回答