【问题标题】:Things are happening outside my for loop before its done (javascript)在完成之前,事情发生在我的 for 循环之外(javascript)
【发布时间】:2011-06-01 01:16:54
【问题描述】:

我确定我以前见过这个并且知道答案,但 12 小时后......我的脑子完全糊涂了。

我有一个 for 循环,我在其中尝试连接到一个字符串,以便在完成字符串(从而完成一个漂亮的小表格)之后,我希望插入到我的 html 中并显示给用户。

但是,我的函数末尾的东西(在我的 for 循环之后)在 for 循环之前被调用......

function getEntries() {

$('#entryTotalsDiv').html('<img src="images/ajax-loader.gif" /> ... retrieving form totals.');

var entryTotalsTable = "<table id='entryTable' class='display' style='border:1px;'><thead><tr><th>Form Name</th><th>Hash</th><th>Entries</th></tr></thead>" +
        "<tbody>"

//Get rows ONE at a time.
var countNumber = 1;
for (var frm = 0; frm < numberOfForms; frm++) {
    $.post('ajax/getEntries.aspx',
    {
        'formNumber': frm
    },
    function (data) {
        entryTotalsTable += "<tr><td>" + data[0].formName + "</td><td>" + data[0].formHash + "</td><td>" + data[0].formEntryCount + "</td></tr>";

        //Now go and update the Form Retrieval div -- add 1 to the frm Number
        $('#formNamesDiv').html(countNumber + ' of ' + numberOfForms + ' retrieved.');
        countNumber++;            
    });
}
entryTotalsTable += "</tbody></table>";
$('#entriesDiv').html(entryTotalsTable);
//Now bind the table to the DataTables JQ script
$('#entryTable').dataTable();
$('#entryTable').show('slow');

}

如果您注意到,我想在最后关闭 Table html,但是在我的 for 循环完成之前调用它,从而搞砸了我的字符串...

entryTotalsTable += "</tbody></table>";
$('#entriesDiv').html(entryTotalsTable);
//Now bind the table to the DataTables JQ script
$('#entryTable').dataTable();
$('#entryTable').show('slow');

}

【问题讨论】:

  • 您正在循环内发出 Ajax 请求。 Ajax 是异步的,因此循环之后的代码在 Ajax 回调执行之前执行。
  • numberOfForms 在哪里定义?还是我的脑子也糊涂了??
  • @Felix:这应该是一个答案。 :)
  • 另一个注意事项:我认为你甚至不能依赖回调按循环顺序调用的事实。来自较早查询的响应可能比来自较晚查询的响应更早收到。
  • @cHao:Imo 一个答案将解决问题....这只是解释 为什么它不起作用....我累了 ;)

标签: javascript loops for-loop


【解决方案1】:

解决方案可能是将每个响应保存在一个数组中,并在每个回调中测试当前计数是否等于总计数。比如:

var countNumber = 1,
    allData = [];

function runWhenFinished() {
    if(countNumber === numberOfForms) {
        var entryTotalsTable = "<table id='entryTable' class='display' style='border:1px;'><thead><tr><th>Form Name</th><th>Hash</th><th>Entries</th></tr></thead>" + "<tbody>";

        for(var i = 0, l = allData.length; i < l; i++) {
             entryTotalsTable += "<tr><td>" + allData[i].formName + "</td><td>" + allData[i].formHash + "</td><td>" + allData[i].formEntryCount + "</td></tr>";
        }

        entryTotalsTable += "</tbody></table>";
        $('#entriesDiv').html(entryTotalsTable);
        //Now bind the table to the DataTables JQ script
        $('#entryTable').dataTable();
        $('#entryTable').show('slow');
    }
}

for(var frm = 0; frm < numberOfForms; frm++) {
    (function(frm) {
        $.post('ajax/getEntries.aspx',{'formNumber': frm}, function (data) {
            allData[frm] = data[0];
            countNumber++;
            $('#formNamesDiv').html(countNumber + ' of ' + numberOfForms + ' retrieved.');
            runWhenFinished();
        });
    }(frm));
}

我确信这仍然可以改进,但你明白了。


如果您确实提出了 70 个请求,那么您可能需要重新考虑您的策略。 70 个并发请求很多。

例如您可以提出 一个 请求并证明应该检索/更新/无论方法正在做什么的最小和最大数量。

【讨论】:

  • +1 - 没有真正回答问题,但确实提供了更好的选择。
  • 感谢您的建议——我正在做计数的事情,然后当计数达到我的限制时才调用下一个函数。我一次打一个电话而不是一个大电话(就像我正在做的那样)的原因是我试图给用户一些反馈(所以每次返回时,我都会更新返回给用户的计数 -一个电话只花了很长时间)**我还认为动态填写我的表会非常酷,这是有效的,但是所有好的 jquery gridview 东西都没有得到应用(即分页等)所以我离开了。
【解决方案2】:

$.post 是异步的,这意味着它会尽快触发循环中的所有请求,然后退出循环。它不等待响应。当响应返回时,您的行函数将被调用...但到那时,所有帖子都已发送完毕。

在此处查看此问题的答案... How can I get jQuery to perform a synchronous, rather than asynchronous, Ajax request?

您需要从 $.post 更改为 $.ajax

【讨论】:

  • 进行多个同步 Ajax 调用可能会导致浏览器(或至少页面)冻结!超过 100 毫秒的所有内容都会被用户注意到。
  • 非常正确 - 希望 numberOfForms 不超过 2!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-11-25
  • 1970-01-01
  • 2012-06-26
  • 1970-01-01
  • 2018-06-07
相关资源
最近更新 更多