开发者

AJAX call in for loop won't return values to correct array positions

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开发者_Python百科 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.


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.


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.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜