Javascript 在导出到CSV之前,如何重构以等待AJAX查询完成?

Javascript 在导出到CSV之前,如何重构以等待AJAX查询完成?,javascript,jquery,ajax,Javascript,Jquery,Ajax,我有下面的代码触发按钮点击。当我运行它时,CSV已创建,但为空。console.log(rows)输出与预期一致,但有一条注释说下面的值刚刚计算过。 如何使exportToCsv的执行等待AJAX调用完成 $("#downloadBtn").click(function() { weeks = getWeeks(startDate.val(), endDate.val()); // start downloading the data for (i=0; i< we

我有下面的代码触发按钮点击。当我运行它时,CSV已创建,但为空。
console.log(rows)
输出与预期一致,但有一条注释说下面的
值刚刚计算过。

如何使exportToCsv的执行等待AJAX调用完成

$("#downloadBtn").click(function() {
    weeks = getWeeks(startDate.val(), endDate.val());
    // start downloading the data
    for (i=0; i< weeks.length; i++) {
        // contains $.ajax query that appends to "rows"
        fetchDataWeek( weeks[i][0], weeks[i][1] );  
    }
    console.log(rows);
    exportToCsv( fileName, rows );            
});

AJAX调用是异步的。代码在加载数据之前执行。为了防止这种情况发生,您应该使用回调函数,并在其他地方对使用AJAX加载的数据执行任何操作。

以下是一些通用代码,以帮助您理解:

$("#downloadBtn").click(function() {
    weeks = getWeeks(startDate.val(), endDate.val());
    // start downloading the data

    // Create an array to hold all your promises
    var promiseArray = [];

    for (i=0; i< weeks.length; i++) {
        // contains $.ajax query that appends to "rows"
        var _promise = Q.defer(); // Create a promise (using https://github.com/kriskowal/q)

        // send this promise to the ajax callback
        fetchDataWeek( weeks[i][0], weeks[i][1], _promise );
        promiseArray.push(_promise)  // Push this promise into the array
    }

    Promise.all(promiseArray).then( function () { // Wait for all promises to resolve
        console.log(rows);
        exportToCsv( fileName, rows );
    })            
});

如果您使用的是JQuery,承诺如下(使用基本身份验证访问端点,这是安全的):


在回调中执行
exportToCsv
。您的意思是在
for
循环中触发ajax查询?在这种情况下,您需要创建一个
承诺的数组,每个
承诺对应一个ajax
。然后,当所有这些文件都已完成时,执行
exportToCsv
resolved@surajck,那会是什么样子?这是jQuery的第1天me@surajck,或者有比for循环更好的方法来构造它吗?在其最简单的形式中,您可以在异步请求的回调函数中增加一个计数器,如果该计数器已达到请求数,则调用导出函数。但您可能也希望对错误做出反应,否则,如果其中一个请求因任何原因失败,您的导出可能永远不会启动。Promissions将是一种更高级的方法。我理解这一点,但我不确定如何进行重构,以便在
exportToCsv
之前完成所有AJAX调用。您究竟在用AJAX查询什么?它是一个PHP脚本吗?如果是,我会将循环移动到PHP并在那里输出所需的数组,因此您只需要一个AJAX调用,就可以在回调函数中执行您想要的任何操作。不,这是一个我无法控制的外部API,一次只能访问一周。在这种情况下,surajck提出了一个优秀的解决方案,请使用它。这不是确切的代码,
Promise
语句的语法会因您使用的库而有所不同。现在查看一下。谢谢我确信这是正确的方法,但我犯了一个错误。我已经编辑了这个问题来添加细节。我建议你使用promise库。试试这个:@JamieBull,我已经编辑了我的答案以适应更新后的问题
$("#downloadBtn").click(function() {
    weeks = getWeeks(startDate.val(), endDate.val());
    // start downloading the data

    // Create an array to hold all your promises
    var promiseArray = [];

    for (i=0; i< weeks.length; i++) {
        // contains $.ajax query that appends to "rows"
        var _promise = Q.defer(); // Create a promise (using https://github.com/kriskowal/q)

        // send this promise to the ajax callback
        fetchDataWeek( weeks[i][0], weeks[i][1], _promise );
        promiseArray.push(_promise)  // Push this promise into the array
    }

    Promise.all(promiseArray).then( function () { // Wait for all promises to resolve
        console.log(rows);
        exportToCsv( fileName, rows );
    })            
});
function fetchDataWeek( startDay, endDay, _promise ) {
    startDay = makeDateString(startDay);
    endDay = makeDateString(endDay);
    url = "https://api" + startDay + endDay + ".json";
    $.ajax({
        url: url,
        success: function(result){
            parseHistory(result);
            _promise.resolve(result); // resolving that promise here
        },
        error: function (error) {
            _promise.reject(error) // rejecting it in case of error
        }
    });            
}
      var url = "/myEndpoint/";       

      var req = $.ajax
      ({
        type: "GET",

        xhrFields: 
        {
          withCredentials: true
        },
        headers: 
        {
          'Authorization': 'Basic ' + btoa(gAccountName + ':' + gAccountPw)
        },
        url: url,
        dataType: 'json'
    });

    req.done(function(data)
    {
      // The data var has your results
      // process here

      console.log(data);          


    });

    req.fail(function(data)
    {

      alert("There was an error loading your list of names. Please try again in a few seconds."); 
    });
  }