【问题标题】:jquery deferred turn failure into successjquery deferred 把失败变成成功
【发布时间】:2011-09-09 16:47:23
【问题描述】:

所以在使用 jQuery deferreds 和 $.when 来并行加载许多对象。

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

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

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

我实际上想要一种表达方式:

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

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

【问题讨论】:

标签: jquery jquery-deferred promise


【解决方案1】:

如果你想捕获一个promise的失败并将其转换为成功,你可以使用then的failFilter来返回一个resolved的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.
});

注意,较早的答案建议使用pipe 方法。从 jQuery 1.8 开始,该方法已被弃用。

【讨论】:

  • 任何想法为什么这不起作用?我试过了,它仍然会失败
  • 失败处理程序(“then”的第二个函数)返回一个已解决的承诺很重要。一个失败的 Promise 或任何不是 Promise 的值都将允许链继续到另一个失败处理程序。
【解决方案2】:

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

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

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

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

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

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

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

【讨论】:

    【解决方案3】:

    您可以通过包装 $.Deferred 对象来相当轻松地构建 $.onFailSucceed

    $.onCompleteSucceed = function(oldDfd) {
        var newDfd = $.Deferred();
    
        oldDfd.always(newDfd.resolve);
    
        return newDfd.promise();
    }
    

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

    $.when(
      a.ajax(), $.onCompleteSucceed(b.ajax()), c.ajax()
    ).then(...)
    

    【讨论】:

    • 不错的解决方案,只是它不会将b.ajax() 的结果传递给.then() 处理程序。
    【解决方案4】:

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

    how to fool jqXHR to succeed always

    lonesomeday 的回答很简洁,但不是我想要的。

    【讨论】:

    猜你喜欢
    • 2017-08-08
    • 1970-01-01
    • 1970-01-01
    • 2016-03-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-09-12
    • 1970-01-01
    相关资源
    最近更新 更多