How to chain ajax requests?

15,938

Solution 1

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);

Solution 2

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!

Solution 3

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.

Solution 4

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.

Solution 5

Update: I've learn a better answer for this if you are using jQuery, see my update under the title: Using jQuery Deffered

Old answer:

You can also use Array.reduceRight (when it's available) to wrap the $.ajax calls and transform a list like: [resource1, resource2] into $.ajax({url:resource1,success: function(...) { $ajax({url: resource2... (a trick that I've learn from Haskell and it's fold/foldRight function).

Here is an example:

var withResources = function(resources, callback) {
    var responses = [];
    var chainedAjaxCalls = resources.reduceRight(function(previousValue, currentValue, index, array) {
        return function() {
            $.ajax({url: currentValue, success: function(data) {
                responses.push(data);
                previousValue();
            }})
        }
    }, function() { callback.apply(null, responses); });
    chainedAjaxCalls();
};

Then you can use:

withResources(['/api/resource1', '/api/resource2'], function(response1, response2) {
    // called only if the ajax call is successful with resource1 and resource2
});

Using jQuery Deffered

If you are using jQuery, you can take advantage of jQuery Deffered, by using the jQuery.when() function:

 jQuery.when($.get('/api/one'), $.get('/api/two'))
       .done(function(result1, result2) { 
              /* one and two is done */
        });
Share:
15,938
defnull
Author by

defnull

Updated on June 22, 2022

Comments

  • defnull
    defnull almost 2 years

    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?