在执行下一步之前需要进行多个异步调用JS

问题描述:

我有一个数组,它可以容纳未知数量的索引。每个索引用于通过ajax呼叫发送数据。我正在通过for loop收集成功调用的数据并将其推入空数组。在未知数量的调用结束时,我需要在我的视图中使用新聚集的数组。 newDataArray在循环完成之前在底部执行,因此它仍然是空的。我如何完成所有的电话,然后做底部的事情?在执行下一步之前需要进行多个异步调用JS

如果有帮助,我正在使用Flux模式进行React。但是同样的问题可能不会在React中完成。这里是什么,我试图做一个模拟样本:

JS

case 'execute-calls': 

    //This is the new array to push to 
    var newDataArray = []; 
    //Url to call 
    var url = 'http://dev.markitondemand.com/Api/v2/Quote/jsonp'; 

    for(let i = 0; i < payload.data.length; i++){ 

     //given array of data that needs to be sent with call 
     let symb = { symbol: payload.data[i]}; 
     $.ajax({ 
      data: symb, 
      url: url, 
      dataType: "jsonp", 
     }) 
      .done(function(data){ 
      let updatedData = { 
       //...data that is stored from response 
      }; 

      newDataArray.push(updatedData); 
      }) 
      .fail(function(error){ 
      //console.log(error); 
      }); 

     } 

    //This will be updating the state object which is above the switch cases 
    //However this is ran before the end of the loops so newDataArray is empty 
    var updateTicker = { 
     updatedTicker: true, 
     updatedTickerSymbols: newDataArray 
    }; 
    assign(stockData,updateTicker); 
    getStockData.emitChange(); 

    break; 

可以使使用$.ajax()实际返回deferred object ,并用它来创建一个延迟数组。例如

var symbols = [1, 2, 3, 4]; 

var deferreds = symbols.map(function (symbol) { 
    return $.ajax({ 
    url: 'http://dev.markitondemand.com/MODApis/Api/v2/Quote/jsonp', 
    data: { symbol: symbol }, 
    dataType: 'jsonp' 
    }); 
}); 

您可以用$.when()一次解决多个延期。但是有一个复杂的问题,$ .when()需要一个参数列表而不是数组。我们可以通过使用Function#apply来解决这个问题。

要添加到并发症,回调函数也被称为参数列表。由于我们不知道有多少个参数,我们将使用arguments伪数组。由于参数不是实际的数组,我们将通过使用Function#callArray#prototype进行循环。

$.when(...deferreds).done((...responses) => { 
    responses.forEach((response) => { 
    console.log(response[0].Message); 
    }); 
}); 
+0

这种方式似乎最直观:

$.when.apply($, deferreds).done(function() { Array.prototype.forEach.call(arguments, function (response) { console.log(response[0].Message); }); }).fail(function (jqXHR, textStatus, error) { console.error(error); }); 

如果您使用ES6这是更优雅[修订包括失败()调用]

。感谢你的回答。你如何看到从响应中是否发生错误?它会被存储在其中一个索引中吗? '$ .when.apply($,deferreds).done(function(response){'那里的控制台日志记录响应会显示错误? – Chipe

+1

好点,还有一个失败的回调函数,当遇到第一个错误时会调用它我相应地更新了代码。 –

当过你正在处理Ajax调用,并有在所有异步年底做一些操作调用,那么更好的选择会是使用Callback函数。

修改代码以使用回调,

function AsyncLoopHandler(index) { 
    if (index > payload.data.length) { 
     // all the indexes have finished ajax calls do your next step here 

     var updateTicker = { 
      updatedTicker: true, 
      updatedTickerSymbols: newDataArray 
     }; 
     assign(stockData, updateTicker); 
     getStockData.emitChange(); 
    } 
    else { 
     //given array of data that needs to be sent with call 
     let symb = { symbol: payload.data[index] }; 
     $.ajax({ 
      data: symb, 
      url: url, 
      dataType: "jsonp", 
     }) 
      .done(function (data) { 
       let updatedData = { 
        //...data that is stored from response 
       }; 

       newDataArray.push(updatedData); 
       AsyncLoopHandler(index++); // call the function again with new index 
      }) 
      .fail(function (error) { 
       //console.log(error); 
      }); 
    } 
} 

现在启动这个递归函数只是路过

AsyncLoopHandler(0); 

因此,所有的Ajax调用将被执行的索引0

启动如同一个同步请求一样,并且 if检查将会看看所有的索引是否完整,然后运行你的逻辑。让我知道,如果这有助于

建议使用承诺,逻辑想在新标准

var urls= [x,x,x,x]; 
 
var results = []; 
 
var qs = $.map(urls,function(url){ 
 
    return function(){ 
 
    var deferred = Q.defer(); 
 
    $.ajax({ 
 
     success:function(){ 
 
     results.push(url) 
 
     deferred.reslove(); 
 
     },error:function(){ 
 
     deferred.reslove();   
 
     } 
 
    }) 
 
    return deferred; 
 
    } 
 
}) 
 
Q.all(qs).then(function(){ 
 
    console.log(results) 
 
});

或使用产量和合作https://github.com/kriskowal/q