开发者

jquery deferred turn failure into success

So in using jQuery deferreds and $.when to load many objects in parallel.

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

Now, b.ajax() will sometimes fail, but I dont actually care. I just want to wait until all the calls have completed before calling complete().

Unfortunately, as soon as b fails, the when() rejects, and never 开发者_Python百科fires the then()callback. This is AFAIK expected behaviour for $.when(), however dosent suit me in this case.

I effectively want a way to say:

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

Or perhaps there is a different way to use when(), or a more suitable construct?


If you want to capture the failure of a promise and convert that to a success, you can use the failFilter of then to return a resolved promise, like so:

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

Doing this will ensure that the chain can continue past the failure unbroken.

So, for your example, you might do this:

$.when([
   a.ajax(),
   b.ajax().then(function(answer) { 
       return answer; 
   }, function() {
       return $.Deferred().resolve({}).promise();
   }),
   c.ajax()
]).then(function(results) {
    // etc.
});

Example 2: In my applications, I sometimes use then to get relational data for a particular entity and allow for the possibility of a 404 to indicate that no such relationship exists:

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

Note, older answers suggest using the pipe method. This method is deprecated as of jQuery 1.8.


Here is something better than hacking a failure into a success.

Little known fact, $.when() will execute the then() callback immediately if any one of the parameters fails. It's by design. To quote the documentation:

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. 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.

There's actually no built-in way of waiting until all of them are finished regardless of their success/failure status.

So, I built a $.whenAll() for you :) It always waits until all of them resolve, one way or the other:

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


You could build $.onFailSucceed fairly easily by wrapping the $.Deferred object:

$.onCompleteSucceed = function(oldDfd) {
    var newDfd = $.Deferred();

    oldDfd.always(newDfd.resolve);

    return newDfd.promise();
}

You could then wrap the appropriate calls in this method:

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


So i figured it out in the end, see my answer to someone else with the same issue:

how to fool jqXHR to succeed always

lonesomeday's answer was neat, but not quite what i was after.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜