I'm writing an app that at one point needs to get the result some number of requests before proceeding. This seems like a likely candidate for using JQuery's when
. eg:
// requests is an array of Deferreds
$.when.apply(null, requests).done(function(results) {
// process results
}
The catch is that the number of requests could be 1 or it could be more, and the when
function handles these cases differently. With only 1 request, the callback gets the standard (data, textStatus, jqXHR) arguments, however when multiple requests are supplied the callback receives a sequence of arguments: an array of (data, textStatus, jqXHR) values for each of the requests. Frustratingly, JQuery seems to be treating a singleton array of requests the same as a single argument request, meaning that this case must be handled differently.
The best I could come up with to tease these cases apart feels kinda clunky and took me a while to figure out due to the subtleties of the resultant arguments in the different cases, and then there's the rookie gotcha of the request array needing to be wrapped up in a function so that it can be accessed in the closure.
$.when.apply(null, function (){return requests;}()).done(function(results) {
if (requests.length == 1) {
processResults(results);
} else {
for (var i=0; i < arguments.length; i++)
processResults(arguments[i][0]);
}
moreStuff();
});
Is there a better or more elegant way than this?
I see this is an older question, but this issue came up for me recently and I came across this question while searching on the issue. I ended up created my own solution so I thought I'd share it as an answer here.
In a nutshell,
$.when()
is really not designed very well for use with dynamic numbers of arguments. In fact, it kind of sucks for dynamic arguments. It is both hard to use and inconsistent in its behavior.It appears that the designers of the ES6 promises specification agree because the analog there
Promise.all()
is designed differently and solves both these problems. So, the best thing I could think of to deal with jQuery's$.when()
issue is to make a new version of it that follows thePromise.all()
rules and is thus simpler to use. Life is further complicated by the fact that jQuery Ajax promises return an array of three values which interacts with$.when()
in the odd ways you mentioned.So, there are two main changes to
$.when()
to make a$.all()
:Make it so that it accepts an array of promises, not separate arguments of promises. This keeps you from having to use
.apply()
just to send a variable number of promises to$.all()
.Make it so that the results form
$.all()
are always in array form, no matter how many promises were originally passed in. This is the inconsistency that you ask about in your question. Fortunately, it doesn't take a lot of code to fix this.It can be done like this:
You use it just like
$.when()
except that you always pass$.all()
a single argument that is an array of promises (no need for.apply()
any more) and it always resolves to a single argument that is an array of results (much easier to iterate dynamic numbers of promise results and it is always consistent).So, if you had an array of ajax promises of arbitrary length: