Reputation: 13804
Sequential Asynchronous calls are gross. Is there a more readable solution?
The problem is this is hard to follow:
ajaxOne(function() {
// do something
ajaxTwo(function() {
// do something
ajaxThree()
});
});
where the anonymous functions are callbacks that are called on server response.
I'm using a third party API to make the AJAX calls, so I need a generic solution.
Upvotes: 5
Views: 1144
Reputation: 1718
First I have to admit, I'm relatively new to JavaScript, but I recently encountered the same problem while using the jQuery ajax function. I had to upload a couple of documents via POST to a server in a certain order. Nesting all the call backs would have produced completely messed up code. I thought about a solution after reading the answers and came up with a solution that worked fine me. It uses only one function with a switch clause to differentiate the different callback invocations:
var callback = function(sCallIdentifier, callbackParameters){
switch(sCallIdentifier){
case "ajaxOne":
doYourStuff(callbackParameters); //do your stuff for ajaxOne
ajaxTwo(function(newCallbackParameters){
/*define a anonymous function as actual method-callback and pass the call-identifier, together with all parameters, to your defined callback function*/
callback("ajaxTwo", newCallbackParameters);
});
break;
case "ajaxTwo":
doYourStuff(callbackParameters);
ajaxThree(function(newCallbackParameters){
callback("ajaxThree", newCallbackParameters);
});
break;
case "ajaxThree":
doYourStuff();
break;
}
});
If this is not a good idea, please let me know. As I said, I'm not a JavaScript expert but I it worked pretty well for me.
Best, René
Edit:
After a while I found out that Promises are a much better approach to solve this problem.
Upvotes: 1
Reputation: 4514
functional programming to the rescue! jsdeferred lets you write your example like so:
next(ajaxOne).next(ajaxTwo).next(ajaxThree).error(function(e){alert('An error happened:' + e)})
each of the "sequential" ajaxOne/Two/Three functions receives the returned result of its predecessor as parameter. If you need to pass in additional parameters, you can expose them in a global object before you invoke your ajax chain.
Upvotes: 3
Reputation: 15832
If you don't need the closure scope in your callbacks, which you probably won't, you can just put the callbacks into separate functions and call them by their name. like:
var ajaxOne = function() {
doTheAjax(callbackOne);
}
var callbackOne = function() {
//funny things ...
doTheAjax(callbackTwo);
}
var callbackTwo = function() {
//even more funny things ...
}
Upvotes: 0
Reputation: 5849
If you have only one nested function, it's Ok to leave it as is, but if you have several nested calls, you should consider writing these callbacks in a separate method, and calling it from the nested function...
ajaxOne(function(result) { handleAjaxOneCallback(result, someExtraNeededArg); } );
function handleAjaxOneCallback(result, someExtraNeededParam) {
// do something
ajaxTwo(function(result) { handleAjaxTwoCallback(result, myFoo, myBar); });
}
function handleAjaxTwoCallback(result, foo, bar) {
// do something
ajaxThree(/* ... */);
}
Upvotes: 1