jQuery Deferred,$ .when()和fail()回调参数

时间:2011-04-01 19:55:57

标签: javascript jquery jquery-deferred

当其中一个延迟操作未成功时使用$.when()时,我收到了意外结果。

使用此JavaScript,创建2个延迟。第一个成功,第二个失败。

var f1 = function() {
    return $.Deferred(function(dfd) {
        dfd.resolve('123 from f1');
    }).promise();
};

var f2 = function() {
    return $.Deferred(function(dfd) {
        dfd.reject('456 from f2');
    }).promise();
};

$.when(f1(), f2())
    .then(function(f1Val, f2Val) {
        alert('success! f1, f2: ' + JSON.stringify([f1Val, f2Val]));
    })
    .fail(function(f1Val, f2Val) {
        alert('fail!    f1, f2: ' + JSON.stringify([f1Val, f2Val]));
    });

自己运行:http://jsfiddle.net/r2d3j/2/

我得到fail! f1, f2: ["456 from f2", null]

问题是在.fail()回调中,随f2()拒绝传递的值被路由到第一个参数,我期望f1Value。这意味着我真的没有办法知道哪个延迟对象实际发布了reject(),而且我也不知道故障数据实际属于哪个操作。

我原以为.fail()会得到参数null, '456 from f2',因为第一次延期没有失败。或者我只是没有在这里做正确的延期?

如果不遵守回调中的参数顺序,我如何知道哪些延迟失败,哪些拒绝参数属于哪个延迟失败?

5 个答案:

答案 0 :(得分:25)

如果任何一个参数失败,

$.when()将立即执行失败的回调(传递给then()的第二个参数)。这是设计的。引用文档:

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

  

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

实际上没有内置的获取回调的方法,无论其成功/失败状态如何,都会等待所有回调完成。

所以,我为你建了$.whenAll() :) 它总是等待,直到所有人都以某种方式解决:

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

$.whenAll(a, b, c)
    .then( callbackUponAllResolvedOrRejected );

答案 1 :(得分:5)

在内部,“拒绝”和“失败”路径由两个完全独立的队列处理,因此它不会按照您期望的方式工作。

为了知道“when()”组中哪个原始Deferred失败,您可以让它们与“.reject()”调用一起传递,作为对象文字或其他内容的一部分。

答案 2 :(得分:0)

我遇到了同样的问题,我通过使用.always回调并检查我的延迟对象数组来处理它。我有一个未知数量的ajax调用,所以我必须执行以下操作:

// array of ajax deletes
var deletes = [];
$checkboxes.each(function () {
    deletes.push(deleteFile(this));
});

$.when.apply($, deletes)
  .always(function () {
      // unfortunately .fail shortcircuits and returns the first fail,
      // so we have to loop the deferred objects and see what happened.

      $.each(deletes, function () {
          this.done(function () {
              console.log("done");
          }).fail(function () {
              console.log("fail");
          });
      });
  });

deleteFile方法返回一个promise,它有.done或.fail回调。

这允许您在所有延期完成后采取行动。在我的情况下,我将显示删除文件错误摘要。

我只是试过这个,不幸的是我不得不放一个间隔计时器来检查它们是否都是在延迟对象的$ .each之后完成的。这看似奇怪而且违反直觉。

仍然试图了解这些延期!

答案 3 :(得分:0)

  

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

如果给定多个输入,这将始终拒绝。 rejected = true;应为rejected |= reject;

答案 4 :(得分:-1)

很老的问题,但现在,要等到 all 都解决了,您可以使用 Promise.allSettled,因为 $.ajax 处理标准承诺。

<块引用>

从 jQuery 1.5 开始,$.ajax() 返回的 jqXHR 对象实现了 Promise 接口,为它们提供了 Promise 的所有属性、方法和行为

因此您可以使用

Promise.allSettled([$.ajax(), $.ajax()])
  .then((res) => {
    if (res[0].status === 'fulfilled') {
      console.log(res[0].value)
      // do something
    } else {
      console.error('res1 unavailable')
    }

    if (res[1].status === 'fulfilled') {
      console.log(res[1].value)
      // do something
    } else {
      console.error('res2 unavailable')
    }
  })