Reputation: 9542
I am sure it looks like this question has been asked a lot before, but it's not the typical async JS question "how to call a function only when another one has finished?".
So my scenario is the following: I need to load a pretty heavy set of data with AJAX, a list of matches arranged in the weeks where they're played. I set up an array of promises and when they're all done I do something else once I have all the matches in the DOM. I had something like this:
var promises = [];
for (var i = 1; var i <= lastWeek; i++)
promises.push($.ajax({
url: "week/" + i,
success: { ... }
}));
$.when.apply($, promises).done(someFunction);
However I noticed this would fire all requests at once and could clog the process in the server side and malfunction in general. So I figured I would approach this differently, instead of making all those requests at once I make one for the first week, and once that one's done, I make the following, and so on:
function loadWeek(week, last) {
$.get("week/" + i, function (response) {
// do whatever with the response
// make the request for the next week
if (week + 1 <= last)
loadWeek(week + 1, last);
});
}
Now of course I cannot use $.when
because the promises are generated on the fly as the previous one is completed.
I wonder if there is a way JS or jQuery offers to signal the someFunction
function (the one that should be called only after all matches have been loaded) after the last week has been loaded.
Of course, you could say, just call it when week + 1 > last
right? Well, I still need to work with promises because this someFunction
not only needs to wait for these matches to be loaded but also for another promise to complete.
So you could say I lied a little when I said I was doing this:
$.when.apply($, promises).done(someFunction);
When in reality, promises
actually have more function calls other than the list of matches, and someFunction
should have until all of them have finished.
Upvotes: 1
Views: 1364
Reputation: 197
Ok so lets break this down, if I understood you correctly you want the following
A- Load weeks sequentially
function loadWeek(week, last) {
var deferred = $.Deferred();
(function request(week, last) {
$.get("week/" + i, function (response) {
// do whatever with the response
// make the request for the next week
if (week + 1 <= last)
request(week + 1, last);
else
deferred.resolve();
});
})(week, last);
return deferred.promise();
}
B- Load other stuff in the mean time
function otherStuff() {
// return some promise
}
C- when A and B are done call someFunction
var promises = []
promises.push(loadWeek(1, 10));
promises.push(otherStuff(...));
$.when.apply($, promises).done(someFunction);
Upvotes: 1
Reputation: 138557
You want a function that runs when a promise, and a function finishes. Small Workaround:
var c=0;
function callbyboth(){
c++;
if(c==2){
//both executed
//run your code
}
}
Add this on your promise
Promise.then(callbyboth);
And at the recursive function:
if(week+1>=last){
callbyboth();
}else{
//recursion
}
Upvotes: 0
Reputation: 1075815
There are several ways, but one of the simplest is to just make a small tweak to your attempt (see ***
):
function loadWeek(week, last, done) { // ***
$.get("week/" + i, function (response) {
// do whatever with the response
// make the request for the next week
if (week + 1 <= last) {
loadWeek(week + 1, last, done); // ***
} else { // ***
done(); // ***
} // ***
});
}
then only push the other promises into promises
(not the ones from loadWeek
above), and:
loadWeek(1, lastWeek, function() {
$.when.apply($, promises).then(someFunction);
});
Upvotes: 0