用于for循环的异步ajax处理的Javascript闭包

时间:2017-01-19 11:35:55

标签: javascript ajax reactjs asynchronous

我有如下的数组。

var clients = ['a','b'];
var reports = ['x','y','z'];
var finalData = [];

现在我需要像这样循环。

for(var i=0;i<reports.length;i++){
   var response = {report : reports[i]}
   for(var j=0;j<clients;j++){
       response.client = clients[i];
      $.ajax({
        url :url,
        success : function(data){
          response.data = data;
          finalData.push(response);
        })
     });
   }
}

由于ajax是异步的,所以它无法正常工作。 另外,我需要将它包装到react.js componentDidMount函数中,并将finalData推送到状态。

我尝试$.each而不是for循环和.bind(this)将最终数据推送到状态。但我没有得到正确的数据。我听说过应该使用异步调用关闭,但是没有得到如何在这里实现。 我正在寻找的输出是。

finalData = [
        {client:a,report:x,data : 'xyz'},
        {client:b,report:x,data : 'xyz'},
        {client:a,report:y,data : 'xyz'},
        {client:b,report:y,data : 'xyz'},
        {client:a,report:z,data : 'xyz'},
        {client:b,report:z,data : 'xyz'}
     ]

1 个答案:

答案 0 :(得分:0)

您必须为响应变量保存范围(使用colsure),请尝试以下操作:

for(var i=0;i<reports.length;i++){
   var response = {report : reports[i]}
   for(var j=0;j<clients;j++){
      response.client = clients[i];

      (function(responce){
      $.ajax({
        url :url,
        success : function(data){
          response.data = data;
          finalData.push(response);
        })
      })(responce);

     });
   }
}

让我们解释一下,模拟ajax将在示例中使用setTimeout

让我们考虑这个例子,它的循环5次,一秒后将需要打印i我们期望打印0 1 2 3 4但实际上它将打印5次5次因为for循环在1秒之前结束消耗,然后在搜索i时打印i,在这种情况下= 5

for(var i=0;i<5;i++){
  setTimeout(function(){
    console.log(i);
    console.log("....");
  }, 1000) 
}

并解决这个需要有一个范围来保存i的值,所以当超时结束时它可以找到i的正确值,称为闭包:

for(var i=0;i<5;i++){
  (function(i){
    setTimeout(function(){
      console.log(i);
      console.log("....");
    }, 1000)
  })(i);
}

此代码将按预期工作,将正确打印0 1 2 3 4,这就是您的示例所做的。

并且为了更新状态,您可以在每次收到值时更新它:

var that = this; // to be added in top of the 2 for loops
finalData.push(response);
this.setState({data: finalData})

或者您可以检查是否为所有客户端加载了所有报告,然后更新状态:

// total can be calculated by num of reports X number of clients
if(finalData.length == total){
  this.setState({data: finalData})
}