JS - console.log(..) 在 for 循环内的回调函数之后输出

JS - console.log(..) outputs following the callback function which is inside for loop

这是一个 Freecodecamp 项目 (TwitchTV),它显示了几个频道的数据,包括直播、onlive 和所有。虽然我可以得到预期的结果(成功显示不同频道的数据),但我无法理解一个问题(因为社区没有提供满意的反馈,所以我在 Whosebug 中再次 post 这个问题)。希望能得到很好的回答。

这是我的代码:

var usernames = ["ESL_SC2", "OgamingSC2", "cretetion", "freecodecamp", 
"storbeck", "habathcx", "RobotCaleb", "noobs2ninjas", "MedryBW"];
 var html_all = "";
 var html_live = "";
 var html_offline = "";


$(document).ready(function() {
 console.log("document ready");
 getChannelData();
});


// get JSON data for channels profile 
function getChannelData(i) {
  for (var i = 0; i < usernames.length; i++)
    {
      $.ajax({
         type: 'GET',
 // url: 'https://api.twitch.tv/kraken/channels/twitch/',
 url: 'https://wind-bow.glitch.me/twitch-api/channels/' + usernames[i],
 error: function() {
    console.log("error occurred when getting channel data");
 },
  success: function(data) {
   displayData(data); 
  }       
});
}
console.log("hi");
console.log(html_all);
button_click();
//   $(".data").html(html_all); // no data displayed 
}


 /* function: 
 display the channels list
 */
  function displayData(data){
    var logo = "<img src="+data.logo+" target='_blank' />";
    var name = "  <span style='font-size:20px;'>" + data.display_name +"</span>";
    var url = data.url;
    var status = data.status;
    var baseurl = "<a href=" + url + " target='_blank'>" + logo + name;
    html_all += baseurl+"</a>"+"<br>";
    $(".data").html(html_all);

    console.log('test');
    if (status != null) {
    // live list
    html_live += baseurl + "<p>" + status + "</p></a>" +"<br>";
  }
  else {
  // offline list
  html_offline += baseurl + "</a>"  +"<br>";
  }
 }


 /* function:
 add click event to buttons
 */
 function button_click(){
   $("button.button-all").on("click", function() {
   $(".data").html(html_all);
  // console.log(html_all); // test
  });
   $("button.button-live").on("click", function() {
   $(".data").html(html_live);
  });
  $("button.button-offline").on("click", function() {
  $(".data").html(html_offline);
 }); 
} 

我的问题:定义的getChannelData()函数中,for()循环后,语句console.log(html_all)输出"",为空。但是全局变量html_allfor()循环之后已经更新了,为什么这里是空的。但是函数 button_click() 按预期工作。如果你在 codepen 中打开我的源代码,所有按钮都可以正常工作。我不明白,如果 for 循环后 html_all 仍然为空,为什么可以在 button_click() 函数中访问变量 html_all 的值?回调函数$.ajax({... success: function()有作用吗?

我认为问题在于 getChannelData 进行了异步调用 AJAX。如果将 console.log(html_all) 放入 success 回调中,您应该会看到预期的结果。

基本上,在加载文档时,会调用您的 getChannelData,但 AJAX 请求需要时间才能完成;在那段时间里,文档会继续处理您的脚本,包括 console.log(html_all)。 AJAX 调用已完成并设置了 html_all 变量,因此 button_click() 和其他所有内容都将正常工作,就在 console.log(html_all) 语句完成之后。

jQuery ajax 默认情况下,请求是异步发送的,这意味着请求被关闭并且代码在继续执行其余逻辑之前不会等待响应。当请求最终返回时,它会被评估以查看请求是否成功,然后适当的代码是 运行(例如,.success(...).fail(...) 等)。

因此,这里可能发生的情况是 for 循环中触发的所有 AJAX 请求都已发送,但其中 none 已收到响应, 到 console.log(html_all); 时。这意味着 displayData 还没有被调用,所以 html_all 的值还没有被更新并且仍然包含它被初始化的默认空字符串值。