2
votes

I'm making a script for some large queries and to avoid timeouts on php side, plus giving the user some input, I'm trying to make most of it on jquery.

So it works like this: First the user select one record on a select. When he clicks the button, I got a ajax call to get the details I need from that record on json format.

With the response, I got a loop that makes ajax calls for each result from that first call.

If I set async to false it works, but the browser freezes because there are several ajax calls. So is there a way to update the ui with async turned off?

I mean, the fact I need to set async to off when I'm making ajax calls inside a loop doesn't make any sense for me. It can make severals calls at same time, I'm fine with that, but why doesn't it get the current index inside that loop unless I set async to false? It keeps using the first index.

    $("#button_copy").live('click', function(){
        $('#button_copy').attr("disabled", true);
        id = $('#select').val();
        $.ajax({
            type: "POST",
            url: "query1.php",
            dataType: 'json',
            async:false,
            cache: false,
            data: 'id=' + id,
            success: function( data ) {
                var total1 = data['records'].length;
                $("#console").append('Total query 1: ' + total1 + '<br />');
                for (var i in data['records']) {
                    $.ajax({
                        type: "POST",
                        url: "query2.php",
                        dataType: 'json',
                        async:false,
                        cache: false,
                        data: 'id=' + data['records'][i].id,
                        success: function( data2 ) {
                            var total2 = data2['records2'].length;
                            $("#console").append('Total of query 2 from ' + data['records'][i].person + ': ' + total2 + '<br />');
                        },
                        error: function(data2) {
                            console.log(data2);
                        }
                    });
                    var percentprogress1 = (i / total1) * 10000;
                    $('#progressbar1').css('width',percentprogress1 + '%');
                }
            },
            error: function(data) {
                console.log(data);
            }
        });
    });
2
What happens when you change your loop to for(var i=0; i < total1; i++) {...} ?Kippie
Looks like it doesn't even get the [0] on the array when I do that. I changed to i=1; < (total 1 -1), it misses some of the records but the result is the same, it just uses the first value on the array on all ajax calls.Paulo Manrique
You should use only one ajax request for that which will returns all results only onceA. Wolff

2 Answers

2
votes

You'll get problems because you're trying to use i inside the callbacks, but by the time the callbacks are invoked i no longer has its original value. You also shouldn't use for ... in on array - only on objects.

Instead of using any sort of for loop, I suggest the following, where each successive AJAX call is triggered on completion of the previous one:

$.ajax(...).done(function(data) {

    var all = data.records;
    (function next() {
        var record = all.shift();
        if (record) {
            $.post(...).done(next, function(res) {
                // process inner result
                // update UI, etc
                ...
            });
        }
    })();       // invoke immediately

});

Note that I've used "deferred" syntax instead of passing success: handlers in the two AJAX calls.

Inside the "pseudo recursive" loop note that I've use .done(next, ...) which allows the loop to start the next AJAX call in parallel with the processing of the results of the current call.

1
votes

I just ran into a similar problem myself. I was running a series of ajax requests in a while loop. Some calls were not being made! It was killing me!! My conclusion was that my browser -- Google Chrome -- ignores "duplicate" requests.

Take a look at this pseudo code:

while (i < ajaxCallArray.length) {
    currentAjaxObject = ajaxCallArray[i];
    ajaxPost = $.post(currentAjaxObject.url, function(data) {
    //response data needs to go into a function such that each request gets its own "data" variable created.otherwise it just overwrites data!!
    processAjaxResponse(data, currentAjaxObject);
        },"json");
i++;
}

If ajaxCallArray[0].url = "http://www.google.com", ajaxCallArray[1].url = "http://www.google.com", and ajaxCallArray[2].url = "http://www.google.com" the browser will only actually make 1 call!!

The solution: You have to do something like ajaxCallArray[0].url = "http://www.google.com?count=0", ajaxCallArray[1].url = "http://www.google.com?count=0", and ajaxCallArray[2].url = "http://www.google.com?count=0" even if you dont use those url parameters, just put something to make them distinct. That way the browser will process all the calls, even if they are done instantly.

Hope this helps!!