Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

Tags:

I'm getting an unexpected result when using $.when() when one of the deferred operations does not succeed.

Take this JavaScript, which created 2 deferreds. 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/

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

I would have expected that .fail() would get arguments null, '456 from f2' since the first deferred did not fail. 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?

like image 463
Alex Wayne Avatar asked Apr 01 '11 19:04

Alex Wayne


People also ask

What is fail in jQuery?

fail() method in jQuery is used to add handlers which are to be called when the Deferred object is rejected. This method accepts one or more than one arguments, which can be either a function or an array of functions.

What is jQuery callback function?

jQuery Callback Functions JavaScript statements are executed line by line. However, with effects, the next line of code can be run even though the effect is not finished. This can create errors. To prevent this, you can create a callback function. A callback function is executed after the current effect is finished.

What is Deferred method in jQuery?

The Deferred object, introduced in jQuery 1.5, is a chainable utility object created by calling the jQuery. Deferred() method. It can register multiple callbacks into callback queues, invoke callback queues, and relay the success or failure state of any synchronous or asynchronous function.


2 Answers

$.when() will execute the failed callback (2nd parameter passed to then()) 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 getting a callback that waits untils 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/51/

$.whenAll(a, b, c)     .then( callbackUponAllResolvedOrRejected ); 
like image 158
InfinitiesLoop Avatar answered Oct 13 '22 20:10

InfinitiesLoop


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.

like image 38
Pointy Avatar answered Oct 13 '22 22:10

Pointy