getJSON函数中覆盖的变量值

Thinh的曹

我正在应对一个挑战,必须显示脱机和在线的Twitch频道。这里是有漏洞的函数:

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();
}

channe_list是一个预先装有频道名称的字符串数组。定义如下:

var channel_list = ["ESL_SC2", "OgamingSC2", "cretetion", "freecodecamp", "storbeck", "habathcx", "RobotCaleb", "noobs2ninjas"];

我的代码只是通过channel_list,获取JSON数据,然后返回结果并创建Channel对象的新实例,定义为:

var Channel = function(name, status){
  this.name = name;
  this.status = status;
}

由于某些原因,在我的else块中,变量“ offlineName”总是被channel_list数组的最后一个值'noobs2ninjas'覆盖。换句话说,当我创建的其他块的通道类的一个实例,“offlineName”总是“noobs2ninjas”。请让我知道我在这里做错了。这是我的CodePen如果你想看看整个事情:

https://codepen.io/tcao2/pen/XNbbbm?editors=1010

维尼

这是你的问题

你可能知道的多快地for循环运行(以及它的速度非常快),但你的网络是不是很快在所有的时候相比,这是什么原因导致你problem.Let我解释

您正在使用$ .getJSON与有其价值取决于URL offlineName,但使用的是offlineName在您的成功回调too.Now假设为第一REQ。offlineName是“ ESL_SC2”,现在ajax请求在URL中使用它,但是照常,由于网络延迟,响应不会立即到达,同时循环正在进行第二次迭代。但是现在是offlineNameIS“ OgamingSC2”!并且将被使用,这样当您的第一个请求的成功回调完成但等待更多的条目时,即使是“ OgamingSC2”也将在以后消失。此外,循环是如此之快,以至于第一个或第二个响应进入时,您的循环已经在其最后一次迭代所以只有最终offlineName值(noobs2ninjas)幸存,然后在所有其他人的成功回调使用。

解决方案:解决方案是找到某种方式来保持每次迭代的offlineName值并在其相应的成功回调中使用值。最简单的方法是使用let声明URLofflineName限制每次迭代的范围,其本质上提供与关闭

https://codepen.io/vsk/pen/LbNpBQ

只有与上面的代码的问题是,let是最近才加入和旧的浏览器不支持它好,所以其他的解决办法是,以真正实现每个请求封闭传递URLofflineName

(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);

https://codepen.io/vsk/pen/rWeOGL

编辑:这些都是所谓的自动执行功能,并没有什么特别之处他们只是下面的代码的缩写版本

function hello(url,name){                //line #39
  //your code                           
}                                        //ln #53
hello(URL,offlineName);                  //ln #54

看到它,您会发现它运行得很好,但是当您注释掉该函数(第39,53,54行)时,它又恢复为旧的错误行为。您可能想知道一个简单的函数将如何如此剧烈地改变行为这是方法-全部基于范围链

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

但是关于作用域链的最重要的事情是,即使循环超过了getJson回调中引用的值,仍然只有一件事是您不能直接访问它们,而VM可以。原因是-链中的最后一个函数是回调(记录在列表中),因此要想使VM在将来运行时必须让其生存所需的值,书呆子称其为闭包,内部函数将始终可以访问外部函数中存在的内容,即使以为外部函数也是如此通话结束和控制返回地方else.Note,即使在你早期的bug的代码值都拿到得救唯一的问题是他们得到覆盖了所有的人都只有一个外部函数,即因为loadStreams但是当你创建和调用单独的hello每个人都会创建一个单独的环境(类似于并行世界)。

本质上,它创建作用域链,因此每次迭代都可以拥有不受他人干扰的“自己的空间”。

for loop --> hello() --> getJson's inner function (每次迭代)

你也许会顺利let,但首先看看兼容性图表在http://caniuse.com/#feat=let

本文收集自互联网,转载请注明来源。

如有侵权,请联系 [email protected] 删除。

编辑于
0

我来说两句

0 条评论
登录 后参与评论

相关文章