23

$.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',因为第一个 deferred 没有失败。或者我只是没有在这里做正确的延期?

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

4

4 回答 4

27

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

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

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

实际上没有内置的方法来获取回调,无论它们的成功/失败状态如何,都等到它们都完成。

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

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

$.whenAll(a, b, c)
    .then( callbackUponAllResolvedOrRejected );
于 2011-10-24T20:41:38.557 回答
4

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

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

于 2011-04-01T20:13:51.593 回答
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 方法返回一个具有 .done 或 .fail 回调的 Promise。

这使您可以在所有延期完成后采取行动。就我而言,我将显示删除文件错误摘要。

我刚试过这个,不幸的是,我不得不设置一个间隔计时器来检查它们是否在我的 $.each 延迟对象之后真正完成。这似乎很奇怪且违反直觉。

仍在尝试理解这些延迟!

于 2012-02-17T16:01:34.690 回答
0

非常老的问题,但现在,要等到所有问题都解决,您可以使用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')
    }
  })
于 2021-04-28T19:49:57.953 回答