简体   繁体   English

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

[英]jQuery Deferred's, $.when() and the fail() callback arguments

I'm getting an unexpected result when using $.when() when one of the deferred operations does not succeed. $.when()延迟操作之一没有成功时,我在使用$.when()时得到了意外的结果。

Take this JavaScript, which created 2 deferreds.以这个 JavaScript 为例,它创建了 2 个延迟。 The first one succeeds and the second one fails.第一个成功,第二个失败。

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]));
    });

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

I get fail! f1, f2: ["456 from f2", null]fail! f1, f2: ["456 from f2", null] fail! f1, f2: ["456 from f2", null]

The problem is that in the .fail() callback the value passed with the f2() rejection, is being routed to the first argument, where i expect the f1Value .问题是在.fail()回调中,通过f2()拒绝传递的值被路由到第一个参数,我期望f1Value Which means that I don't really have a way of know which deferred object actually posted that reject() , and I also dont know which operation that failure data actually belongs to.这意味着我真的没有办法知道哪个延迟对象实际发布了reject() ,我也不知道失败数据实际上属于哪个操作。

I would have expected that .fail() would get arguments null, '456 from f2' since the first deferred did not fail.我原以为.fail()会得到参数null, '456 from f2'因为第一个 deferred 没有失败。 Or am I just not doing deferreds right way here?或者我只是在这里没有正确地进行延期?

How do I know which deferreds failed, and which rejection arguments belong to which failed deferred if the argument order in the callback is not respected?如果不遵守回调中的参数顺序,我如何知道哪些延迟失败,哪些拒绝参数属于哪些失败延迟?

$.when() will execute the failed callback (2nd parameter passed to then() ) immediately if any one of the parameters fails.如果任何一个参数失败, $.when()将立即执行失败的回调(传递给then()第二个参数then() It's by design.这是设计使然。 To quote the documentation:引用文档:

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

In the multiple-Deferreds case where one of the Deferreds is rejected, jQuery.when immediately fires the failCallbacks for its master Deferred.在多个延迟的情况下,其中一个延迟被拒绝,jQuery.when 立即为其主延迟触发 failCallbacks。 Note that some of the Deferreds may still be unresolved at that point.请注意,此时某些延迟可能仍未解决。 If you need to perform additional processing for this case, such as canceling any unfinished ajax requests, you can keep references to the underlying jqXHR objects in a closure and inspect/cancel them in the failCallback.如果您需要针对这种情况执行额外的处理,例如取消任何未完成的 ajax 请求,您可以在闭包中保留对底层 jqXHR 对象的引用,并在 failCallback 中检查/取消它们。

There's actually no built-in way of getting a callback that waits untils all of them are finished regardless of their success/failure status.实际上没有内置的方法来获取回调,无论它们的成功/失败状态如何,它都会等待所有这些都完成。

So, I built a $.whenAll() for you :)所以,我为你构建了一个$.whenAll() :)
It always waits until all of them resolve, one way or the other:它总是等到他们都解决了,以一种或另一种方式:

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

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

Internally, the "reject" and "fail" paths are handled by two totally separate queues, so it just doesn't work the way you expect.在内部,“拒绝”和“失败”路径由两个完全独立的队列处理,因此它不会按您期望的方式工作。

In order to know which original Deferred failed from the "when()" group, you could have them pass themselves along with the ".reject()" call as part of an object literal or something.为了知道“when()”组中哪个原始延迟失败,您可以让它们与“.reject()”调用一起作为对象文字或其他东西的一部分传递。

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

This will always reject if given multiple inputs. 如果给定多个输入,这将始终拒绝。 rejected = true; should be rejected |= reject; 应该被rejected |= reject;

I've faced this same problem, and I dealt with it by using the .always callback and inspecting my array of deferred objects.我遇到了同样的问题,我通过使用 .always 回调并检查我的延迟对象数组来处理它。 I had an unknown number of ajax calls, so I had to do the following:我有未知数量的 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");
          });
      });
  });

The deleteFile method returns a promise, which has .done or .fail callbacks. deleteFile 方法返回一个承诺,它具有 .done 或 .fail 回调。

This allows you to take action after all deferreds have completed.这允许您在所有延迟完成后采取行动。 In my case I'm going to show a delete file error summary.就我而言,我将显示删除文件错误摘要。

I just tried this, and unfortunately I had to put a interval timer to check that they were all truly done after my $.each on the deferred objects.我刚试过这个,不幸的是我不得不设置一个间隔计时器来检查它们是否在我的 $.each 之后真正完成了延迟对象。 This seems odd and counterintuitive.这似乎很奇怪且违反直觉。

Still trying to understand these deferreds!仍在努力理解这些延迟!

Very old question but now, to wait until all are resolved, you can use Promise.allSettled since $.ajax deals with standard promises.很老的问题,但现在,要等到所有问题都解决了,您可以使用Promise.allSettled因为$.ajax处理标准承诺。

The jqXHR objects returned by $.ajax() as of jQuery 1.5 implement the Promise interface, giving them all the properties, methods, and behavior of a Promise从 jQuery 1.5 开始,$.ajax() 返回的 jqXHR 对象实现了 Promise 接口,为它们提供了 Promise 的所有属性、方法和行为

Therefore you can use因此你可以使用

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')
    }
  })

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM