Reputation: 2817
I need to get a range of pages using AJAX and put them into an array, where their given place in the array is equal to the i
of a for loop (it's a caching-like function for blog pages, and the range of the for loop is entirely variable). I'm doing something akin to the following:
var bongo = new Array();
for (i = 0; i < 10; i++) {
jQuery.ajax({ type: "GET", url: 'http://localhost', data: queryString, success: function(request) { bongo[i] = request } })
}
The problem is, that unless I add async: false
to the .ajax options (which would make it... SJAX?), which causes the requests to basically pause the browser, going against what I'm trying to do, the i in the success callback will always end up being 11, whereas I of course want it to pour the returned data into each slot of the array from 0 to 10.
I've tried replacing the line with this:
bongo[i] = jQuery.ajax({ type: "GET", url: 'http://localhost', data: queryString }).responseText
But that made no difference.
Upvotes: 16
Views: 12096
Reputation: 11461
You need a closure:
var bongo = [];
for (i = 0; i < 10; i++)
{
(function(i)
{
jQuery.ajax(
{
type: "GET",
url: "http://localhost",
data: queryString,
success: function(request) { bongo[i] = request }
});
})(i);
}
Loops are the #1 place where inline functions stump people. The bongo[i] = result
isn't called until later. The value of i
at that time is different (most likely 11). If you want to "trap" or "capture" the current value of i
, you need to create a new scope. The only way to do that in javascript is with another function.
Upvotes: 39
Reputation: 625087
Try:
var bongo = [];
for (i=0; i<10; i++) {
$.get("http://localhost", function(result) {
bongo.push(result);
}
}
This way each result will simply get pushed onto the array, solving the need for the array indexes to be correct. Order however is not guaranteed. If that is a requirement you'll need another approach.
There are multiple ways to solve this problem. Here is one: create objects for your callback to save state. Here is an example:
function Callback(array, index, result) {
this.array = array;
this.index = index;
this.result = result;
var obj = this;
this.func = function() {
obj.array[obj.index] = obj.result;
};
}
$(function() {
var arr = [];
for (var i=0; i<4; i++) {
var obj = new Callback(arr, i, "result" + i);
setTimeout(obj.func, (5-i) * 100);
}
setTimeout(function() {
console.log(arr);
}, 500);
});
So in your case:
function Callback(array, index) {
this.array = array;
this.index = index;
var obj = this;
this.callback = function(result) {
obj.array[obj.index] = result;
};
}
var bongo = [];
for (i=0; i<10; i++) {
var ob = new Callback(bongo, i);
$.get("http://localhost", ob.callback);
}
Basically the above saves all the data to an object and thus each callback has access to the right information.
Also, bear in mind that most browsers limit the number of concurrent AJAX requests, typically to 2 per host.
Upvotes: 4