Console.log在每个getJSON循环中重复输出

时间:2016-06-24 01:21:19

标签: javascript jquery twitch

有人能告诉我为什么我的console.log为每个循环返回相同的输出以及如何修复它? console.log应该返回'频道的每个元素。数组,但它不断输出最后一个元素' noobs2ninjas'。

它与FCC Twitch应用here的功能类似。不同之处在于我交换了。$ getJSON命令。他们的应用程序正在获得“流”。首先,当我获得“通道”#39;第一。我一直在比较我的代码和他们的代码,并且无法理解为什么内部。$ getJSON将一遍又一遍地重复相同的数组元素但是outter。$ getJSON正在循环遍历每个元素。

function loadChannel() {
    var channels = ["ESL_SC2", "OgamingSC2", "cretetion", "freecodecamp", "storbeck", "habathcx", "RobotCaleb", "noobs2ninjas"];
    var display_name = null;
    var logo = null;
    var url = null;
    var game = null;
    var status = null;
    var online = false;

    function api(type, channel) {
        return `https://api.twitch.tv/kraken/${type}/${channel}?callback=?`;
    }

    for (var index in channels) {
        $.getJSON(api('channels', channels[index]), function(data) {
            display_name = data.display_name;
            logo = data.logo;
            url = data.url;
            game = data.game;
            status = data.status;
            $.getJSON(api('streams', channels[index]), function(data) {
                // get online status
                console.log(channels[index]); // <-- outputs same channel 'noobs2ninjas' each loop
                console.log(data); // <-- outputs same object each loop
            });
        });
    }
}

2 个答案:

答案 0 :(得分:1)

因为$.getJSON是异步的,并且在调用其回调时,循环已经结束,index将保持循环的最新值。

您应该bind将您的函数index作为第一个参数,如:

for (var index in channels) {
  (function(i){
     $.getJSON(api('channels', channels[i]), function(data){
       ...
       // channels[i] is what you want here
       $.getJSON(api('streams', channels[i]), function(data) {
         ...
       });
     });
  }.bind(null, index))()
}

但在这种特定情况下,为什么不channels.forEach(function(channel){ ... }

答案 1 :(得分:1)

这是因为Javascript中的var是函数作用域,而不是块作用域;您的var index声明被提升到loadChannels的顶部,并被覆盖每个循环。这意味着您的异步函数只访问最后一个索引,因为循环在ajax调用之前完成。 一个很好的解决方案,你已经非常接近了。

使用现有代码,您可以只切换for循环,而是使用Array.forEach。您将向它传递一个函数,该函数将创建一个新的作用域,其中 channel 在本地作用于循环(因此在每次迭代时都不会被覆盖)。

function loadChannel() {
    var channels = ["ESL_SC2", "OgamingSC2", "cretetion", "freecodecamp", "storbeck", "habathcx", "RobotCaleb", "noobs2ninjas"];
    var display_name = null;
    var logo = null;
    var url = null;
    var game = null;
    var status = null;
    var online = false;

    function api(type, channel) {
        return `https://api.twitch.tv/kraken/${type}/${channel}?callback=?`;
    }

    channels.forEach(function (channel) {
        $.getJSON(api('channels', channel), function(data) {
            display_name = data.display_name;
            logo = data.logo;
            url = data.url;
            game = data.game;
            status = data.status;
            $.getJSON(api('streams', channel), function(data) {
                // get online status
                console.log(channel); // <-- should be fixed
                console.log(data); // <-- outputs same object each loop
            });
        });
    });
}

将您计划在循环中使用的任何其他变量的声明(display_name,logo等)移动到我们刚刚制作的forEach中也可能是明智之举。

参考文献: