Javascript 在循环中使用ajax填充对象

Javascript 在循环中使用ajax填充对象,javascript,ajax,jquery,Javascript,Ajax,Jquery,我需要从服务器上的一系列.csv文件中提取数据。我正在将CSV转换为数组,并试图将它们全部保存在一个对象中。ajax请求都是成功的,但由于某种原因,只有来自上一个请求的数据最终进入对象。这是我的密码: var populate_chart_data = function(){ "use strict"; var genders = ["Boys","Girls"]; var charts = { WHO: ["HCFA", "IWFA", "LFA", "

我需要从服务器上的一系列.csv文件中提取数据。我正在将CSV转换为数组,并试图将它们全部保存在一个对象中。ajax请求都是成功的,但由于某种原因,只有来自上一个请求的数据最终进入对象。这是我的密码:

var populate_chart_data = function(){
    "use strict";
    var genders = ["Boys","Girls"];
    var charts = {
        WHO: ["HCFA", "IWFA", "LFA", "WFA", "WFL"],
        CDC: ["BMIAGE", "HCA", "IWFA", "LFA", "SFA", "WFA", "WFL", "WFS"]
    };
    var fileName, fileString;
    var chart_data = {};
    for (var i=0; i < genders.length; i++){
        for (var item in charts){
            if (charts.hasOwnProperty(item)){
                for (var j=0; j<charts[item].length; j++) {
                    fileName = genders[i] + '_' + item + '_' + charts[item][j];
                    fileString = pathString + fileName + '.csv';
                    $.ajax(fileString, {
                        success: function(data) {
                            chart_data[fileName] = csvToArray(data);
                        },
                        error: function() {
                            console.log("Failed to retrieve csv");
                        },
                        timeout: 300000
                    });
                }
            }
        }
    }
    return chart_data;
};
var chart_data = populate_chart_data();
var填充图数据=函数(){
“严格使用”;
变量genders=[“男孩”、“女孩”];
var图表={
世卫组织:[“HCFA”、“IWFA”、“LFA”、“WFA”、“WFL”],
CDC:[“体重指数”、“HCA”、“IWFA”、“LFA”、“SFA”、“WFA”、“WFL”、“WFS”]
};
var文件名,fileString;
var图表_数据={};
对于(变量i=0;i数据的工作都必须在ajax回调中完成。您可以这样做:

var requests = [];
var chart_data = {};
/* snip */
requests.push($.ajax(fileString, {
/* snip */

$.when.apply(undefined, requests).done(function () {
    //chart_data should be full
});

这里有两件事需要考虑:

  • AJAX调用是异步的,这意味着只有在收到数据时才会调用回调。与此同时,循环会继续进行,并对新请求排队

  • 由于循环正在进行,
    filename
    的值将在执行回调之前更改

  • 所以你需要做两件事:

  • 将请求推送到数组中,并仅在数组完成时返回
  • 创建一个闭包,这样文件名就不会更改
  • var图表_数据=[];
    var请求=[];
    
    对于(var j=0;jI认为您可能需要查找闭包的概念如果
    fileName
    不同,这不应该是一个时间问题,但是您可以通过ajax调用中的设置
    async:false
    来测试这一点。您可能需要读取
    fileName
    的值,因为您有一个闭包嵌套在一个循环中。谢谢各位,你们是对的。我在你们发布的一个问题中发现了这一点,它为我澄清了事实:谢谢@Kenneth,它向我介绍了许多伟大的概念并处理了这个问题。非常感谢。没问题,很乐意帮助。请记住,如果答案确实对你有帮助,请接受/支持投票我仍然感到困惑。闭包的定义在最后有
    (文件名)
    。我得到一个错误,因为它还没有定义。我不太清楚应该做什么。另外,应该
    var onSuccess=(函数(文件名){
    be
    var onSuccess=(函数(文件名))吗{
    相反?我是在为那个匿名函数定义一个参数还是传入一个参数?我编辑了答案并更改了一些变量名,这样就不会再让人感到困惑了。实际上,在这一行中,你要做的是创建一个函数并立即调用它,传入
    文件名
    作为一个参数。然后分配返回的value to
    onSuccess
    。该函数有效地返回另一个函数,其好处是在该
    函数中有一个对参数的引用(您以前传入的)。希望这能稍微清除它
    
    var chart_data = [];
    var requests = [];
    
    for (var j=0; j<charts[item].length; j++) {
        fileName = genders[i] + '_' + item + '_' + charts[item][j];
        fileString = pathString + fileName + '.csv';
        var onSuccess = (function(filenameinclosure){               // closure for your filename
                            return function(data){
                                chart_data[filenameinclosure] = csvToArray(data);
                            };
                        })(fileName);
        requests.push(                                     // saving requests
            $.ajax(fileString, {
                success: onSuccess,
                error: function() {
                    console.log("Failed to retrieve csv");
                },
                timeout: 300000
            })
        );
    }
    
    $.when.apply(undefined, requests).done(function () {
        // chart_data is filled up
    });