Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/javascript/430.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Javascript getJSON函数中覆盖的变量值_Javascript - Fatal编程技术网

Javascript getJSON函数中覆盖的变量值

Javascript getJSON函数中覆盖的变量值,javascript,Javascript,我正在进行一项挑战,我必须显示离线和在线的Twitch频道。下面是有bug的函数: function loadStreams(){ for (var i = 0; i < channel_list.length; i++){ offlineName = channel_list[i]; console.log("offline name is: " + offlineName); URL = "https://wind-bow.hyperdev.space/tw

我正在进行一项挑战,我必须显示离线和在线的Twitch频道。下面是有bug的函数:

function loadStreams(){
  for (var i = 0; i < channel_list.length; i++){
    offlineName = channel_list[i];
    console.log("offline name is: " + offlineName);
    URL = "https://wind-bow.hyperdev.space/twitch-api/streams/" + channel_list[i] + "?callback=?";
     $.getJSON(URL, function(data){
       console.log("Now offline name is: " + offlineName);
       console.log(data);
       if (data.stream !== null){
         currChannel = new Channel(data.stream.channel.display_name, data.stream.channel.status);
       }
       else {
         currChannel = new Channel(offlineName, "Offline");
       }       
       outArr.push(currChannel);
    });    
  }
  //showAll();
}
我的代码只需遍历channel_列表,获取JSON数据,返回结果并创建channel对象的新实例,定义如下:

var Channel = function(name, status){
  this.name = name;
  this.status = status;
}
由于某些原因,在my else块中,变量“offlineName”总是被通道列表数组的最后一个值“noobs2nijas”覆盖。换句话说,当我在else块中创建Channel类的实例时,“offlineName”总是“noobs2nijas”。请让我知道我做错了什么。这是我的密码笔,如果你想看看整个事情:

这是您的问题

您可能知道循环的
运行速度有多快(很快),但与之相比,您的网络根本不快,这就是造成问题的原因。让我解释一下

您正在将$.getJSON与URL一起使用,URL的值取决于
offlineName
,但您也在成功回调中使用
offlineName
。现在假设为第一个请求
offlineName
现在是“ESL_SC2”,ajax请求在URL中使用它,但像往常一样,由于网络延迟,响应不会立即到达,同时循环现在正在进行第二次迭代。但是等待
offlineName
现在是“OgamingSC2”!!当您的第一个请求成功回调完成但等待时,将使用该命令,因为还有更多条目,所以即使是“OgamingSC2”也会在稍后被击败。此外,循环速度非常快,以至于在收到第一个或第二个响应时,您的循环已经处于最后一次迭代,因此只有最终的
脱机名称
值(noobs2nijas)生存下来,然后用于所有其他函数的成功回调

解决方案:解决方案是找到某种方法,通过这种方法,每次迭代都会保留其
离线名称
值,并在其相应的成功回调中使用相同的值。最简单的方法是使用
let
声明
URL
离线名称
,这限制了它提供的每次迭代的范围类似于闭包的效果

上述代码的唯一问题是,
let
是最近添加的,而较旧的浏览器不太支持它,因此另一个解决方案是实际实现每个传递
URL
offlineName的请求的闭包

(function(url,name) {
   $.getJSON(url, function(data){
   if (data.stream !== null){
     currChannel = new Channel(data.stream.channel.display_name, data.stream.channel.status);
   }
   else {
     currChannel = new Channel(name, "Offline");
   }       
   outArr.push(currChannel);
  }); 
})(URL,offlineName);

编辑:这些函数称为自执行函数,它们没有什么特别之处,只是下面代码的简写版本

function hello(url,name){                //line #39
  //your code                           
}                                        //ln #53
hello(URL,offlineName);                  //ln #54
你会发现它运行得非常完美,但当你注释掉函数(第39、53、54行)时,它又回到了原来的错误行为。你可能想知道一个简单的函数怎么能如此彻底地改变行为。下面是如何-它都是基于作用域链的

就像Java一样,JS解释器(以下称为VM)现在一行一行地读取代码,当它到达
hello
的定义时,它只是读取它(研究参数、返回和内部代码),然后继续;现在它已经到达调用hello(URL、offlineName);它在hello中运行代码,但随后它意识到,
getJson
有一个回调,此时无法调用,因此它会将其记录在“以后调用”列表中,以及该函数当时使用的所有变量的值[1]。因此,即使在以后的循环迭代中,
URL
offlineName
重新初始化/分配了新值,它们也不会影响[1]中绑定的值,因为它们与它们没有关系,它们是完全不同的实体。这是因为JS按值传递参数(至少对于基本类型)

但关于作用域链最重要的一点是,即使在循环越过
getJson
回调中引用的值之后,仍然存在唯一的问题是您不能直接访问它们,而VM可以。原因是-链中的最后一个函数是回调(记录在列表中)因此,为了让VM在将来运行时能够保留所需的值,书呆子们称之为闭包,在闭包中,内部函数将始终能够访问外部函数中存在的内容,即使外部函数调用已经结束,并且控制权已返回到其他地方。请注意,即使在您之前的错误代码中,值也会得到s唯一的问题是它们都被覆盖了,因为它们都只有一个外部函数,即
loadStreams
,但当您创建并调用单独的
hello
s时,每个函数都会创建一个单独的环境(类似于平行宇宙)

本质上,它创建了范围链,因此每个迭代都可以有自己的“空间”,在那里不受其他人的干扰

for循环-->hello()-->getJson的内部函数
(每次迭代)


你可能会喜欢
但是首先看一下兼容性图表,在非常感谢你的回复新手!有趣的是,问题在于网络的速度和循环运行的速度(我习惯了Java,刚刚开始学习js和web开发)。第一个解决方案对我来说很有意义(我将不得不研究“let”关键字),但是对于第二个解决方案,闭包做了什么?非常感谢!!
function hello(url,name){                //line #39
  //your code                           
}                                        //ln #53
hello(URL,offlineName);                  //ln #54