How to chain ajax requests?

I have to interact with a remote api that forces me to chain requests. Thats a callback-hell in asynchronous mode:

// pseudocode: ajax(request_object, callback)
ajax(a, function() {
  ajax(b(a.somedata), function() {
    ajax(c(b.somedata), function() {
      c.finish()
    }
  }) 
})

It would be much more readable in sync mode:

sjax(a)
sjax(b(a.somedata))
sjax(c(b.somedata))
c.finish()

But Sjax is evil :) How do I do that in a nice not-so-evil and readable way?


You could have a single function which is passed an integer to state what step the request is in, then use a switch statement to figure out what request needs to be make next:

function ajaxQueue(step) {
  switch(step) {
    case 0: $.ajax({
              type: "GET",
              url: "/some/service",
              complete: function() { ajaxQueue(1); } 
    }); break;
    case 1: $.ajax({
              type: "GET",
              url: "/some/service",
              complete: function() { ajaxQueue(2); }
            }); break;
    case 2: $.ajax({
              type: "GET",
              url: "/some/service",
              complete: function() { alert('Done!'); }
            }); break;
  }
}

ajaxQueue(0);

Hope that helps!


Don't use anonymous functions. Give them names. I don't know if you're able to do what I wrote below though:

var step_3 = function() {
    c.finish();
};

var step_2 = function(c, b) {
    ajax(c(b.somedata), step_3);
};

var step_1 = function(b, a) {
  ajax(b(a.somedata), step_2);
};

ajax(a, step_1);

This function should chain together a list of ajax requests, if the callbacks always return the parameters necessary for the next request:

function chainajax(params, callbacks) {
  var cb = shift(callbacks);
  params.complete = function() {
    var newparams = cb(arguments);
    if (callbacks)
      chainajax(newparams, callbacks);
  };
  $.ajax(params);
};

You can define these callback functions separately and then chain them together:

function a(data) {
  ...
  return {type: "GET", url: "/step2.php?foo"}
};
// ...
function d(data) { alert("done!"); };

chainajax({type: "GET", url: "/step1.php"},
  [a, b, c, d]);

You could also declare the functions "inline" in the call to chainajax, but that might get a little confusing.


Maybe what you can do is write a server-side wrapper function. That way your javascript only does a single asynchronous call to your own web server. Then your web server uses curl (or urllib, etc.) to interact with the remote API.