使用$ .when()等待一切都执行甚至失败

时间:2013-03-09 02:12:22

标签: jquery wait jquery-deferred

使用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();
});

有更好的方法吗?

2 个答案:

答案 0 :(得分:3)

了Jonatan,

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

  • 短语作为jQuery实用程序方法,如$.when()
  • 允许个人承诺或一系列承诺传递
  • 如果
  • 中没有传递任何参数或空数组,则立即解析
  • 容忍非承诺/非延期
  • 允许在每个承诺得到解决或拒绝时报告链的进度。

以下是代码:

(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);

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

似乎工作 - DEMO

答案 1 :(得分: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
    });