3

I have these ajax calls that need to get called when the previous one is success, meaning once the first ajax is OK, call the 2nd ajax, once the 2nd ajax is OK call the 3rd one, etc so on. I started with a few ajax calls so it was fine to chain them up like this below but now I have about 20 of them and it'd be a mess to chain them up like this.

$.ajax({
    url: 'urlThatWorks1',
    success: function (data) {

        //call someMethod1 with data;

        $.ajax({
        url: 'urlThatWorks2',
        success: function (data) {

             //call method2 with data;
             //another ajax call ... so on
        } 
 }.... 19 level deep

So I need to make it bit easier to read and maintain so I'm thinking something like

var ajaxArray = [];

var function1 = $.ajax('urlThatWorks1', data I get back from the 'urlThatWorks1' call);

myArray.push(function1);

var function2 = $.ajax('urlThatWorks2', data I get back from the 'urlThatWorks2' call);
myArray.push(function2);
//etc 19 others

myArray.each(index, func){
    //Something like $.when(myArray[index].call()).done(... now what?
}

Hope this makes sense, I'm looking for a way of ajax call array from which I can call an ajax call on whose success I call the next ajax in the array. Thanks.

artm
  • 8,554
  • 3
  • 26
  • 43
  • possible duplicate of [How to return the response from an Ajax call?](http://stackoverflow.com/questions/14220321/how-to-return-the-response-from-an-ajax-call) – andrex Sep 19 '14 at 14:25
  • Wrap each ajax call in a function and call the function in the success block? That way you can give each block a meaningful function name and keep things readable – Turnip Sep 19 '14 at 14:28
  • @3rror404 That's what I was thinking as well but how do I manage that inside the myArray.each? Something like $.when(myArray[index].call()).done(... now what? – artm Sep 19 '14 at 14:36
  • @artm It may be off-topic but may I ask what are you trying to do and why need 20 ajax functions ,My reason to ask this is may be we can find an alternate solution where there is no need to have 20 ajax functions. – Suraj Singh Sep 19 '14 at 14:50
  • @SurajSingh I have multiple charts (20 of them) that get their data from ajax calls. I need to call them one after another so once one finishes loading the next one loads. – artm Sep 19 '14 at 15:04
  • @andrex: I don't think this is a dup. The answer there does, about 2/3rds of the way down, provide some nice information on how to improve this kind of code in general by using a Deferred, but the asker seems to already know the general concept (see the comment about `.when`) and just not know how to apply it here. – abarnert Sep 20 '14 at 02:18

4 Answers4

1

How about using the Deferred approach. Something like:

var arrayOfAjaxCalls = [ { url: 'https://api.github.com/', success: function() { $("#results").append("<p>1 done</p>"); } },
                        { url: 'https://api.github.com/', success: function() { $("#results").append("<p>2 done</p>"); } },
                        { url: 'https://api.github.com/', success: function() { $("#results").append("<p>3 done</p>"); } },
                        { url: 'https://api.github.com/', success: function() { $("#results").append("<p>4 done</p>"); } },
                        { url: 'https://api.github.com/', success: function() { $("#results").append("<p>5 done</p>"); } },
                        { url: 'https://api.github.com/', success: function() { $("#results").append("<p>6 done</p>"); } },
                        { url: 'https://api.github.com/', success: function() { $("#results").append("<p>7 done</p>"); } },
                        { url: 'https://api.github.com/', success: function() { $("#results").append("<p>8 done</p>"); } },
                        { url: 'https://api.github.com/', success: function() { $("#results").append("<p>9 done</p>"); } } 
                       ];


loopThrough = $.Deferred().resolve();

$.each(arrayOfAjaxCalls, function(i, ajaxParameters) {
  loopThrough = loopThrough.then(function() {
    return $.ajax(ajaxParameters);
  });
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.0/jquery.min.js"></script>
<div id="results"></div>
mccannf
  • 16,619
  • 3
  • 51
  • 63
1

Create a recursive function to be called in sequence as the ajax requests return data.

var urls = [ "url.1", "url.2", ... ];
var funcs = [];

function BeginAjaxCalls()
{
    RecursiveAjaxCall(0, {});
}

function RecursiveAjaxCall(url_index)
{
    if (url_index >= urls.length)
        return;
    $.ajax(
    {
        url: urls[url_index],
        success: function(data)
        {
            funcs[url_index](data);
            // or funcs[urls[url_index]](data);

            RecursiveAjaxCall(url_index + 1);
        }
    });
}

funcs[0] = function(data)
// or funcs["url.1"] = function(data)
{
    // Do something with data
}

funcs[1] = function(data)
// or funcs["url.2"] = function(data)
{
    // Do something else with data
}
Matt
  • 1,377
  • 2
  • 13
  • 26
  • This looks good except that //do something with data is different for each ajax call, one ajax call success calls method1, another ajax success calls another method so on. There's no single //do something with data – artm Sep 19 '14 at 14:50
  • I don't need to pass previous call's data to the next one, it's just that each success needs to call another method – artm Sep 19 '14 at 14:53
  • Okay, I'll revert to the original answer and then edit it to allow for seperate function calls. – Matt Sep 19 '14 at 14:54
  • Although not exact, this is the answer closest to what I ended up doing so I'm accepting it. – artm Sep 25 '14 at 08:09
1

Try

$(function () {
    // requests settings , `url` , `data` (if any)
    var _requests = [{
        "url": "/echo/json/",
        "data": JSON.stringify([1])
    }, {
        "url": "/echo/json/",
        "data": JSON.stringify([2])
    }, {
        "url": "/echo/json/",
        "data": JSON.stringify([3])
    }];

    // collect responses
    var responses = [];

    // requests object ,
    // `deferred` object , `queue` object
    var requests = new $.Deferred() || $(requests);

    // do stuff when all requests "done" , completed
    requests.done(function (data) {
        console.log(data);
        alert(data.length + " requests completed");
        $.each(data, function (k, v) {
            $("#results").append(v + "\n")
        })
    });

    // make request
    var request = function (url, data) {
        return $.post(url, {
            json: data
        }, "json")
    };

    // handle responses
    var response = function (data, textStatus, jqxhr) {
        // if request `textStatus` === `success` ,
        // do stuff
        if (textStatus === "success") {
            // do stuff 
            // at each completed request , response
            console.log(data, textStatus);
            responses.push([textStatus, data, $.now()]);
            // if more requests in queue , dequeue requests
            if ($.queue(requests, "ajax").length) {
                $.dequeue(requests, "ajax")
            } else {
                // if no requests in queue , resolve responses array
                requests.resolve(responses)
            }
        };
    };

    // create queue of request functions
    $.each(_requests, function (k, v) {
        $.queue(requests, "ajax", function () {
            return request(v.url, v.data)
            .then(response /* , error */ )
        })
    })

        $.dequeue(requests, "ajax")

});

jsfiddle http://jsfiddle.net/guest271314/6knraLyn/

See jQuery.queue() , jQuery.dequeue()

guest271314
  • 1
  • 15
  • 104
  • 177
0

You could use the async library, which has a bunch of functions like waterfall or series which could solve your problem.

https://github.com/caolan/async#series

https://github.com/caolan/async#waterfall

ploutch
  • 1,204
  • 10
  • 12