关于html:JavaScript变量被困在循环内 – 无法访问

JavaScript Variable Stuck inside Loop - Can't Access

我正在进行AJAX调用以检索某个州的所有商店。 问题是,最后两行是否无法访问我在get调用的return函数中构建的任何变量内容。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
    var states = ['TX', 'AZ];

    for(j = 0; j < states.length; j++) {
        var fullHTML = '
';
        var full2;
        $.get("//127.0.0.1:8000/api/state-stores/", {state: states[j]}, function(data) {
            console.log(data.stores.length);

            for(var i = 0; i < data.stores.length; i++) {
                store_html = '
<tr><td>' + data.stores[i].name + '</td><td>'
                fullHTML += store_html;
            }
        })
        // PROBLEM HERE
        console.log(fullHTML); //empty
        $("#" + states[j].toLowerCase() +"-table").html(fullHTML); //does nothing
    }

我该怎么做才能解决这个问题? 我一直在尝试奇怪的全局变量技巧和各种各样的hack-y事情,但没有任何工作。

UPDATE
我也尝试将最后两行放在$.get调用中,但states[j]由于某种原因在循环内无法访问。
在调试之后,似乎只有来自外部循环的j在此返回函数内是不可访问的。 有办法解决这个问题吗?

更新2

我按照答案中给出的建议,我正在为fullHTML获得正确连接的字符串,但是,每个fullHTML字符串只替换表中的最后一个状态。 就好像TX标签是唯一接收所有更新的标签。 我认为这是基于闭包的,但我不知道如何解决这个问题。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
$(function() {
    var states = ['AZ', 'CA', 'CO', 'GA', 'NV', 'NC', 'SC', 'TX'];
    // var states = ['CA'];
    for(var j = 0; j < states.length; j++) {
        var current = j;
        $.get("//127.0.0.1:8000/api/state-stores/", {state: states[j]}, function(data) {
            var fullHTML = '';
            for(var i = 0; i < data.stores.length; i++) {
                store_html = '<tr><td>' + data.stores[i].name + '</td><td>' + data.stores[i].address + '<span class="small-table">' + data.stores[i].city + '</span></td><td>' + data.stores[i].city + '</td><td>' + data.stores[i].state + '</td><td>' + data.stores[i].postal_code + '</td></tr>'
                fullHTML += store_html;
            }
            $('#' + states[current].toLowerCase() + '-table').html(fullHTML);
        })  
    }

});


这是一个异步的$ .get函数。也就是说,代码执行不会在该行等待,直到$ .get完成,执行回调函数,然后继续到$ .get之后的下一行。实际上,它将对$ .get函数执行异步调用,并继续立即执行到console.log(fullHTML)行。此时无法保证$ .get函数已完成甚至启动,因为它是异步执行的。

至于您对j的可访问性的问题,这是一个回到闭包的问题。在$ .get回调中访问时,j变量将引用已经循环的j变量,并将返回不正确的j值,因为您可能需要j的值从$ .get请求执行时开始。所以,你需要将j存储在本地闭包中,方法是将它明确地声明为var current = j,而不是在$ .get回调中引用j,你引用current,然后它会按预期执行。这不起作用!

编辑

如果我们声明一个匿名函数并在该上下文中执行$ .get,我们可以强制创建一个新的作用域。这不是一个漂亮的解决方案,但它的工作原理!

要修复代码,请将调用放在$ .get回调中,如下所示:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
var states = ['TX', 'AZ'];

for(j = 0; j < states.length; j++) {
    var fullHTML = '';
    var full2;
    (function() {
        var current = j;
        $.get("//127.0.0.1:8000/api/state-stores/", {state: states[j]}, function(data) {
            console.log(data.stores.length);

            for(var i = 0; i < data.stores.length; i++) {
                store_html = '<tr><td>' + data.stores[i].name + '</td><td>'
                fullHTML += store_html;
            }
            console.log(fullHTML); // not empty anymore
            $("#" + states[current].toLowerCase() +"-table").html(fullHTML); //does stuff
        });
   })();
}

现在,您的代码只会在填充fullHTML变量之前执行已损坏的行。