Fletcher Moore
Fletcher Moore

Reputation: 13804

How to avoid nested functions when using AJAX?

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

Answers (4)

rene
rene

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

fbuchinger
fbuchinger

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

selfawaresoup
selfawaresoup

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

Pablo Cabrera
Pablo Cabrera

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

Related Questions