Console.log 在每个 getJSON 循环中重复输出
Console.log repeating output in each getJSON loop
有人能告诉我为什么我的 console.log 为每个循环返回相同的输出以及如何修复它吗? console.log 应该返回 'channels' 数组的每个元素,但它一直输出最后一个元素 'noobs2ninjas'.
它与 FCC Twitch 应用程序的功能相似 here。不同之处在于我交换了 .$getJSON 订单。他们的应用程序首先获得 'stream',而我首先获得 'channel'。我一直在比较我的代码和他们的代码,无法理解为什么内部 .$getJSON 会一遍又一遍地重复相同的数组元素,而外部 .$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
});
});
}
}
因为 $.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){ ... }
?
因为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、徽标等)的声明移动到我们刚刚创建的 forEach 中也是明智的。
参考文献:
有人能告诉我为什么我的 console.log 为每个循环返回相同的输出以及如何修复它吗? console.log 应该返回 'channels' 数组的每个元素,但它一直输出最后一个元素 'noobs2ninjas'.
它与 FCC Twitch 应用程序的功能相似 here。不同之处在于我交换了 .$getJSON 订单。他们的应用程序首先获得 'stream',而我首先获得 'channel'。我一直在比较我的代码和他们的代码,无法理解为什么内部 .$getJSON 会一遍又一遍地重复相同的数组元素,而外部 .$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
});
});
}
}
因为 $.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){ ... }
?
因为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、徽标等)的声明移动到我们刚刚创建的 forEach 中也是明智的。
参考文献: