最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - jQuery whenthenfail with concurrent ajax requests: Which request failed? - Stack Overflow

programmeradmin3浏览0评论

Imagine a scenario where we want to do something after the concurrent requests for 'foo' and 'bar' have completed successfully, or report an error if one or both of them fails:

$.when($.getJSON('foo'), $.getJSON('bar'))
  .then(function(foo, bar) {
    console.log( 'I fire if BOTH requests are successful!' );
  })
  .fail(function() {
    console.log( 'I fire if one or more requests failed.' );
  });

How can I determine if 1) the request for 'foo' failed, or 2) the request for 'bar' failed, or 3) if both failed?

Imagine a scenario where we want to do something after the concurrent requests for 'foo' and 'bar' have completed successfully, or report an error if one or both of them fails:

$.when($.getJSON('foo'), $.getJSON('bar'))
  .then(function(foo, bar) {
    console.log( 'I fire if BOTH requests are successful!' );
  })
  .fail(function() {
    console.log( 'I fire if one or more requests failed.' );
  });

How can I determine if 1) the request for 'foo' failed, or 2) the request for 'bar' failed, or 3) if both failed?

Share Improve this question edited Jun 4, 2011 at 14:46 lonesomeday 238k53 gold badges327 silver badges328 bronze badges asked Apr 26, 2011 at 18:45 JavierJavier 1011 gold badge1 silver badge4 bronze badges 3
  • Have you tried just doing one at a time? – locrizak Commented Apr 26, 2011 at 18:48
  • @locrizak - Imagine an application that requests 'foo' and 'bar' concurrently, but needs both to return successfully before processing them. – Javier Commented Apr 26, 2011 at 18:55
  • why not make both foo and bar return true or false depending on their success or failure, call both functions and save their returns in separate variables? that way you can require both to be true and if not, check which of the two was false. – eagerMoose Commented Apr 26, 2011 at 19:03
Add a comment  | 

3 Answers 3

Reset to default 11

Simply add a fail call to each promise that is returned from $.getJSON:

function make_error_handler(msg) {
    return function() { console.log(msg); };
}

$.when($.getJSON('foo').fail(make_error_handler("foo failed"))
            , $.getJSON('bar').fail(make_error_handler("bar failed")))
  .then(function(foo, bar) {
    console.log( 'I fire if BOTH requests are successful!' );
  })
  .fail(function() {
    console.log( 'I fire if one or more requests failed.' );
  });

If you need more fine-grained control you can overload $.getJSON to return additional information to the fail function -- see jQuery's documentation on deferred.rejectWith

From the documentation on jQuery.when

In the multiple-Deferreds case where one of the Deferreds is rejected, jQuery.when immediately fires the failCallbacks for its master Deferred. 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.

In other words, you are supposed to keep the references to each request, and check it manually yourself, if you need to.

The difficulty is that when the fail callback is called, any number of deferred's can still be outstanding, thus at that state they have neither failed nor succeeded.

I wish the documentation explained a bit better as to exactly what is passed to the fail handler in this case. Judging from the source code though, it seems that the arguments received by the fail handlers depend on which Deferred fails first:

args[ i ].promise().then( resolveFunc(i), deferred.reject );

I'm no expert on jQuery internals, but I think this simply lets each of your Deferred's call the "master" Deferred's reject method with whatever arguments it would normally pass to its handlers. Not ideal, if you ask me... but then I could be misreading this.

I do wonder if they meant this though:

args[ i ].promise().then( resolveFunc(i), func() { deferred.reject(args); } );

You could call .isResolved() to check whether a request did actually complete, but the problem with .when() is that it'll fail as soon as either request fails, so you can't reliably tell whether the other request might be about to fail.

I believe the answer I just posted to a similar question will resolve (no pun intended) this requirement, by creating an extra $.Deferred for each AJAX query, which allows you to wait until you know the actual outcome of both AJAX calls.

发布评论

评论列表(0)

  1. 暂无评论