Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

jQuery.ajax() inside a loop [duplicate]

If I call jQuery.ajax() inside a loop, would it cause the call in current iteration overwrite the last call or a new XHR object is assigned for the new request?

I have a loop that do this, while from console log I can see requests done 200 ok but just the result data of the last request in the loop is stored by the request success callback as supposed .

the code:

var Ajax = {
    pages: {},

    current_request: null,

    prefetch: function () {
        currentPath = location.pathname.substr(1);

        if(this.pages[currentPath])
        {
            var current = this.pages[currentPath];
            delete this.pages[currentPath];

            current['name']=currentPath;
            current['title']=$("title").text().replace(' - '.SITE_NAME, '');
            current['meta_description']=$("meta[name=description]").attr('content');
            current['meta_keywords']=$("meta[name=keywords]").attr('content');          
        }

        var _Ajax = this;
        //the loop in question *****
        for(var key in this.pages)
        {
            $.ajax({
                method: 'get',
                url:'http://'+location.hostname+'/'+key,
                success: function(data) {
                    _Ajax.pages[key] = data;    
                }
            }); 

                    console.debug(this.pages);
        }

        if(current)
        {
            this.pages[currentPath] = current;
        }       

    } 
};//Ajax Obj
for(var i in pages)
{
    Ajax.pages[pages[i]]={};
}

$(function() {
    Ajax.prefetch();
});//doc ready
like image 621
MTVS Avatar asked Jul 31 '13 21:07

MTVS


3 Answers

You need to use async:false in you ajax request. It will send the ajax request synchronously waiting for the previous request to finish and then sending the next request.

$.ajax({
    type: 'POST',
    url: 'http://stackoverflow.com',
    data: data,
    async: false,
    success: function(data) {
        //do something
    }, 
    error: function(jqXHR) {
        //do something
    }
});
like image 180
Yura Zabolotny Avatar answered Nov 09 '22 23:11

Yura Zabolotny


You'll need a closure for key:

for(var k in this.pages){
    (function(key){
            $.ajax({
                method: 'get',
                url:'http://'+location.hostname+'/'+key,
                success: function(data) {
                    _Ajax.pages[key] = data;    
                }
            }); 

            console.debug(this.pages);
    })(k);
}

that way you make sure that key is always the correct on in each ajax success callback. but other than that it should work

i made a small closure demonstration using timeout instead of ajax but the principle is the same:

http://jsfiddle.net/KS6q5/

like image 30
Andy Avatar answered Nov 10 '22 01:11

Andy


I believe what's happening here has to do with closure. In this loop:

    for(var key in this.pages)
    {
        $.ajax({
            method: 'get',
            url:'http://'+location.hostname+'/'+key,
            success: function(data) {
                _Ajax.pages[key] = data;    
            }
        }); 

                console.debug(this.pages);
    }

The variable key is actually defined outside the for loop. So by the time you get to the callbacks, the value has probably changed. Try something like this instead:

http://jsfiddle.net/VHWvs/

var pages = ["a", "b", "c"];

for (var key in pages) {
    console.log('before: ' + key);
    (function (thisKey) {
        setTimeout(function () {
            console.log('after: ' + thisKey);
        }, 1000);
    })(key);
}
like image 41
Jason P Avatar answered Nov 10 '22 01:11

Jason P