Since you are using jQuery, you can use the jQuery Deferred object, which is similar to a regular javascript Promise, in order to control the execution flow of your multiple requests. What you need to do is return a deferred.promise() from the functions where you make the ajax calls, and only resolve() the promise when you are satisfied that the next call has completed successfully, or that there doesn't need to be another ajax call. So you would set up your functions something like this (I have included numbered comments to illustrate the execution order of the code within each function, but be aware that everything inside the second request function happens between steps 3 and 4 of the initial request function):
function makeInitialRequest() {
var initialDeferred = $.Deferred();
// 1. make the initial request
$.ajax({
}).done(function(data) {
// 3. request succeeded
// map through the results to make your second requests,
// but _store_ the returned promises so you know when
// the second requests have all resolved
var secondRequests = data.d.results.map(function(resultItem) {
// the map function here is returning the promisse
// that is returned from the makeSecondRequest function
return makeSecondRequest(resultItem.EmployeeID);
});
// wait until all second requests have finished before
// resolving the initial promise
$.when.apply($, secondRequests).done(function() {
// 4. all second requests completed
// so we can tell the calling function
// that everything is complete and it's ok to proceed
initialDeferred.resolve();
}).fail(function() {
// 4. deal with the error
initialDeferred.reject();
});
}).fail(function(xqXhr, code, error) {
// 3. deal with the error
initialDeferred.reject();
});
// 2. return an unresolved promise
return initialDeferred.promise();
}
function makeSecondRequest(userID) {
var secondDeferred = $.Deferred();
// 1. make request
$.ajax({
}).done(function(data) {
// 3. request succeeded
if (data.d.SomeValue) {
// if you need to make another call, go ahead,
// and wait for that to be finished before resolving the promise
makeThirdRequest(data.d.SomeOtherValue).done(function() {
// 4. the third request succeeded
// so we can tell the makeIntitialRequest function
// that everything is complete and it is ok to proceed
secondDeferred.resolve()
}).fail(function() {
// 4.
});
} else {
// no need to wait for another call,
// so just tell the makeIntialRequest function
// it is ok to proceeed
secondDeferred.resolve();
}
}).fail(function(jqXhr, code, error) {
// 3.
})
// 2. return the promise
return secondDeferred.promise();
}
So you can keep nesting other calls, as long as you make them return deferred.promise()s that you then resolve() when it's ok for the previous function to continue.
(It can also get more complex by calling resolve(someData) with some data, which will actually return that data out to the calling function, but I'm not going to get into that here.)
Then, in your main code, you just do:
// some code
// some code
makeInitialRequest().done(function() {
// continue with your code
// knowing that all nested ajax calls are complete
}).fail(function() {
// deal with failure
});
Oh, also, keep in mind I have rejected the promises on errors, but be aware that that will pass the error state up to the calling function, meaning, in this "main code" example just above, if the makeInitialRequest function calls reject() on the initialDeferred, you will never get to the done function where it says "continue with your code knowing all nested ajax calls are complete". Instead, it will go to the fail function. This is important because sometimes certain errors mean that it's impossible to continue, so you do want to reject those up to prevent further code execution, but sometimes the errors may not mean that it's impossible to continue, so you just may want to try to deal with those locally within the functions where they occur, but still resolve the promise so that the calling function can proceed anyway.