Search code examples
javascriptjqueryfor-loopcallbackcodepen

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


It's a Freecodecamp project (TwitchTV), which displayed several channels data including live stream, onlive, and all. Although I can have expected result (successfully display different channels data), I couldn't understand one issue (since it was not provided satisfied feedback on the community, so I post this question again in stackoverflow). Hopefully it could be answered well.

Here is my code:

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

My question: in the defined getChannelData() function, after the for() loop, the statement console.log(html_all) outputs "", empty. But the global variable html_all is already updated after the for() loop, why is empty in here. But then function button_click() works as expected. If you open my source code in codepen, all button works fine. I don't understand, why variable html_all's value can be accessed in button_click() function if html_all is still empty after for loop? Does the callback function $.ajax({... success: function() play a role?


Solution

  • I think the issue is that getChannelData makes an AJAX call, which is asynchronous. If you put console.log(html_all) inside of your success callback, you should see what you expect.

    Basically, as the document is loaded, your getChannelData is called, but the AJAX request takes time to complete; in that time, the document continues to process your script, including the console.log(html_all). The AJAX call is completed and the html_all variable is set, so the button_click() and everything else will work, just after the console.log(html_all) statement has finished.