8

因此,在使用 jQuery 延迟并$.when并行加载许多对象时。

$.when(
  a.ajax(), b.ajax(), c.ajax()
).then(
  //do something when all are complete
  complete();
);

现在,b.ajax()有时会失败,但我实际上不在乎。我只想等到所有调用都完成后再调用complete()。

不幸的是,一旦b失败,就会when()拒绝,并且永远不会触发then()回调。这是 AFAIK 的预期行为$.when(),但在这种情况下不适合我。

我实际上想要一种方式说:

$.when(
  a.ajax(), b.ajax().fail(return success), c.ajax()
).then(...)

或者也许有不同的使用方式when(),或更合适的构造?

4

4 回答 4

6

如果你想捕获一个 Promise 的失败并将其转换为成功,你可以使用then的 failFilter来返回一个已解决的 Promise,如下所示:

deferredCall.then(function(answer) { 
   // this is success. you might transform the answer here.
   return transformed;
}, function() {
   // this is a fail. you might resolve the fail with an empty object.
   return $.Deferred().resolve({}).promise();
});

这样做将确保链条可以继续通过故障而不会中断。

因此,对于您的示例,您可以这样做:

$.when([
   a.ajax(),
   b.ajax().then(function(answer) { 
       return answer; 
   }, function() {
       return $.Deferred().resolve({}).promise();
   }),
   c.ajax()
]).then(function(results) {
    // etc.
});

示例 2:在我的应用程序中,我有时使用then来获取特定实体的关系数据,并允许 404 指示不存在此类关系:

getEntity(id).then(function(entity) {
    return getAssociation(id).then(function(association) {
        entity.association = association;
        return entity;
    }, function() {
        entity.association = null;
        return $.Deferred().resolve(entity).promise();
    });
}).done(function(entity) {
    // etc.
});

请注意,较旧的答案建议使用管道方法。自 jQuery 1.8 起,此方法已被弃用。

于 2015-05-13T16:00:38.590 回答
3

这比把失败变成成功更好。

鲜为人知的事实是,如果任何一个参数失败,$.when() 将立即执行 then() 回调。这是设计使然。引用文档:

http://api.jquery.com/jQuery.when/

在多个 Deferred 的情况下,其中一个 Deferred 被拒绝,jQuery.when 立即为其主 Deferred 触发 failCallbacks。请注意,此时某些 Deferreds 可能仍未解决。如果您需要针对这种情况执行额外的处理,例如取消任何未完成的 ajax 请求,您可以在闭包中保留对底层 jqXHR 对象的引用,并在 failCallback 中检查/取消它们。

实际上,无论它们的成功/失败状态如何,都没有内置的方法可以等待它们全部完成。

所以,我为你构建了一个 $.whenAll() :) 它总是等到它们全部解决,一种或另一种方式:

http://jsfiddle.net/InfinitiesLoop/yQsYK/

于 2011-10-24T20:38:25.593 回答
1

您可以$.onFailSucceed通过包装$.Deferred对象来相当容易地构建:

$.onCompleteSucceed = function(oldDfd) {
    var newDfd = $.Deferred();

    oldDfd.always(newDfd.resolve);

    return newDfd.promise();
}

然后,您可以在此方法中包装适当的调用:

$.when(
  a.ajax(), $.onCompleteSucceed(b.ajax()), c.ajax()
).then(...)
于 2011-06-07T07:47:43.423 回答
1

所以我最后想通了,看看我对其他有同样问题的人的回答:

如何欺骗 jqXHR 永远成功

lonesomeday 的回答很简洁,但不是我所追求的。

于 2011-06-28T13:20:29.037 回答