如果在for循环中,我如何等待XHR请求结束?

时间:2018-02-12 10:38:00

标签: javascript jquery ajax xmlhttprequest

我已经阅读了很多答案,但在这种情况下我不明白如何解决这个问题。

我有一系列积分和外部网站,我可以确定这点是在陆地还是在海上。问题是for循环不等待XHR请求。

var points = [
  [90, 120],
  [80, 120],
  [70, 120]
];

var land_or_sea = [];
for(var x= 0; x < points.length; x++) {
  var lat_string = points[x][0];
  var lng_string = points[x][1];

  var xhr = new XMLHttpRequest();
  xhr.onreadystatechange = function(){
    if (this.readyState === 4 && this.status === 200){                  
      var obj = JSON.parse(this.responseText);          
        if (obj.water === true){
          land_or_sea.push(x + 1);                      
        }                           
     }
   }
   xhr.open("GET", "https://api.onwater.io/api/v1/results/" + lat_string + "," + lng_string, true);
   xhr.send();
}

如果点数在海上但由于for循环不等待,我应该添加land_or_sea的索引,如何看到points是一个空数组。

我希望你能帮助我。谢谢!

4 个答案:

答案 0 :(得分:1)

我认为你最好的举措是避免这么多的api请求并创建一个api请求来处理坐标列表。但我猜这个api不支持它。

你有没有检查api是否正常,因为我试过了它给了我一个假水,一个空和一个500错误告诉我太多的请求错误。

另一个好处是使用xhr.onload方法,因为每次移动为onreadystatechange定义的函数时都会出现问题,x变量递增到3,因此对于每个后续的readystatechange(例如最终响应),你都会被保留x = 3,因为闭包保持指针,而不是定义时的值。因此,如果这样可行,它将使用值4填充数组,因为您将x + 1设置为[4,4,4]。

要将其包装起来,请使用onload而不是onreadystatechange并密切关注429/500错误。希望这会有所帮助。

答案 1 :(得分:0)

您可以创建递归函数,而不是使用for循环。

您可以将数组索引初始化为0并将其传递给函数。成功响应后,再次使用递增的数组索引调用相同的函数。到达array.length

后停止调用该功能

例如:

var points = [
  [90, 120],
  [80, 120],
  [70, 120]
];

var arrIndex = 0;
var land_or_sea = [];

function callAjaxFunc(arrIndex){
  var lat_string = points[arrIndex][0];
  var lng_string = points[arrIndex][1];

  var xhr = new XMLHttpRequest();
  xhr.onreadystatechange = function(){
    if (this.readyState === 4 && this.status === 200){                  
      var obj = JSON.parse(this.responseText);          
        if (obj.water === true){
          land_or_sea.push(x + 1);    
          if (arrIndex < points.length){
            arrIndex++;
            callAjaxFunc(arrIndex);
          }    
        }                           
     }
   }
   xhr.open("GET", "https://api.onwater.io/api/v1/results/" + lat_string + "," + lng_string, true);
   xhr.send();
}
callAjaxFunc(arrIndex);

答案 2 :(得分:0)

如果您有ES7支持,可以将整个代码包装在异步函数中,只需等待结果即可。创建一个承诺并像这样使用它:(再次,这仅适用于您支持ES7

   (async () => {
var points = [
  [90, 120],
  [80, 120],
  [70, 120]
];

var p = (lat_string, lng_string) => new Promise(res => {
  var xhr = new XMLHttpRequest();
  xhr.onreadystatechange = function() {
    if(this.readyState === 4 && this.status === 200){                  
      res(JSON.parse(this.responseText));            
     }
   }
   xhr.open("GET", "https://api.onwater.io/api/v1/results/" + lat_string + "," + lng_string, true);
   xhr.send();
})

var land_or_sea = [];
for(var x= 0; x < points.length; x++) {
  var lat_string = points[x][0];
  var lng_string = points[x][1];
  var obj = await p(lat_string, lng_string)
  if(obj.water === true) {
    land_or_sea.push(x + 1);                      
  }                       
}
})()

答案 3 :(得分:-1)

您正在寻找的是Synchrounous xhr请求。

XMLHttpRequest.open()方法的完整语法如下:

XMLHttpRequest.open(method, url, async, user, password)

您可以将“async”请求参数设置为“false”。如果此值为false,则send()方法在收到响应之前不会返回。