在进行下一次迭代之前等待ajax成功结束

时间:2012-02-13 14:52:14

标签: jquery ajax asynchronous

我有一个for循环,它遍历一个关联数组。 foreach条目我必须发出ajax请求并用检索到的数据填充另一个数组 问题是成功回调是异步的,所以它只在循环迭代后运行。这意味着我的数据数组中填充了最后一个ajax请求结果的多个副本。 这是我的代码(简化):

var channels = {  
    "misured": "channel_misured",  
    "plan": "channel_plan"  
};
var data;  //Initial data is empty

function getData() {
    data = new Array();

    for (var seriesData in channels) {
        var currentData = new Array();
        $.ajax({
            type: "GET",
            url: 'http://' + serverAddress + ':' + serverPort + '/GetChannelBufferAsJsonp?channelName=' + channels[seriesData] + '&callback=?',
            dataType: "json",
            async: false,
            success: function (json) {
                var time = new Date().getTime() + 3600000;
                for (var i = 0; i < json.length; i++) {
                    currentData.push({
                        x: time + i * 30000,
                        y: json[i]
                    });
                }

                data.push({
                    id: seriesData,
                    name: "Production " + seriesData,
                    data: currentData
                });

            }, error: function () {
                console.log("error", this);
            }
        });
    }
}

所以数据有2个元素(正确),但它们都来自“plan_channel”(这是我的数据源)。 我知道这是ajax请求的经典,众所周知的“问题”(或特征),但我看不出如何摆脱它。
你能说出如何在进入下一次迭代之前等待成功回调结束吗?

2 个答案:

答案 0 :(得分:1)

这是我能看到重构代码的唯一方法(在我的头顶)。虽然它有点无意义。你已经设置了所有错误的IMO,你不应该这样做。我能看到的最好的方法是将整个数组发送到一个ajax请求到ajax脚本,在php(或其他)中处理所有这些并在javascript中以你想要的格式将它吐出来。否则你最好找到一个更好的方法来做到这一点。例如,您可以拥有一个ajax请求,而不是拥有for循环,该请求会在成功调用中回调getData()函数。

// add a global var...
var inLoop;
function getData() {
    data = new Array();

    for (var seriesData in channels) {
        inLoop = true; // set to true
        var currentData = new Array();

        $.ajax({
            type: "GET",
            url: 'http://' + serverAddress + ':' + serverPort + '/GetChannelBufferAsJsonp?channelName=' + channels[seriesData] + '&callback=?',
            dataType: "json",
            async: false,
            success: function (json) {
                // set inLoop to false to get out of loop below
                inLoop = false;
                var time = new Date().getTime() + 3600000;
                for (var i = 0; i < json.length; i++) {
                    currentData.push({
                        x: time + i * 30000,
                        y: json[i]
                    });
                }

                data.push({
                    id: seriesData,
                    name: "Production " + seriesData,
                    data: currentData
                });

            }, error: function () {
                console.log("error", this);
            }
        });

        // loop round this bit for a while
        while(inLoop){
          // wait
        }
    }


}

这就是我重写上面代码的方法:

var channels = {
  "first" : "hello world",
  "second" : "goodbye world"
}

function getData(channel){
  $.ajax({
    url: 'http://whatever.com/channel='+channel,
    success: function(){
      getData(nextchannel);
    }
  });
}

为了做到这一点,你可能需要计算你通过函数或其他东西的时间,以便能够再次将下一个通道传递给函数。

答案 1 :(得分:1)

对于同步AJAX调用,您无法使用成功处理程序,并且必须在调用完成后返回结果。

尝试使用Amplify.js(http://amplifyjs.com/),asyc设置为false;它比jQuery ajax功能更易于使用和更整洁。不要被附加图书馆推迟。

更新#1

你只需要这样做

function getData() {
    data = new Array();

    for (var seriesData in channels) {
        var currentData = new Array();


    amplify.request.define( "ajaxExample1", "ajax", {
        url: 'http://' + serverAddress + ':' + serverPort + '/GetChannelBufferAsJsonp?channelName=' + channels[seriesData] + '&callback=?',
        dataType: "json",
        async: false,
        type: "GET"
    });

    // later in code
    amplify.request( "ajaxExample1", function( json ) {
        var time = new Date().getTime() + 3600000;
        for (var i = 0; i < json.length; i++) {
            currentData.push({
                x: time + i * 30000,
                y: json[i]
            });
        }

        data.push({
            id: seriesData,
            name: "Production " + seriesData,
            data: currentData
        });
    });

    }
}