0

new at this, please tell me if I'm leaving information out or anything like that.

The code I'm working on can be seen here: http://codepen.io/hutchisonk/pen/mVyBde and I have also pasted the relevant section of javascript below.

I'm having trouble understanding why this code is behaving as it is. Quick outline - I have defined a few variables at the top, made a function that fetches the data I need and builds it into a pretty little list. This seems to be working as planned.

With the function outlined, I then loop through each "friend" in the "friends" array, calling the function once each time. I have numbered the friends on the output to help clarify what is going on. I have tried this a number of ways, including with the "for loop" syntax that's currently implemented, as well as the "forEach" syntax that's commented out.

Two main questions:

1) The number in front of each name is the "i" in my for loop. Why is this "i" not going in order from 0 to 10? How do I get it to do so? It appears to be in a different order every time the code is run. And, it repeats the numbers it has looped through previously on each new iteration. I would like to understand why this is happening.

2) The code seems to be running out of order. The unexpected behavior can be seen in the console.log - the for loop outputs the first two lines of console.log on a loop, then jumps out and console.logs the test variable "a" and the other text below the for loop, and then jumps back into the for loop and console.logs the output from the function. I'm looking at the console in google chrome and I did read that there can be timing inconsistancies with regard to the console, but I don't understand how the loop is being split in half - the first two lines, and then the function call being logged after the later code.

What is the best way to iterate through an array? Any insights on how to call a function within a loop correctly or resources you can provide are much appreciated.

$("document").ready(function(){

  var friends = ["lainzero", "freecodecamp", "storbeck", "terakilobyte", "habathcx","RobotCaleb","thomasballinger","noobs2ninjas","beohoff", "dtphase", "MedryBW"];
  var html = "";
  var url = "";

  function getStreamingData(eachfriend, number) {
     url = "https://api.twitch.tv/kraken/streams/"+eachfriend;

  $.ajax({
  dataType: "jsonp",
  url: url,
  success: function(result) {
      console.log(result+", "+result.stream);

    if(result.stream !== null) {
      html+= "<li class='streaming'><a href='twitch.tv/"+eachfriend+"'>"+number+": "+eachfriend;
      html +="<i class='fa fa-play-circle style='font-size:20px;color:green;''></i>";
    } else if (result.stream === null) {
      html+= "<li class='not_streaming'><a href='twitch.tv/"+eachfriend+"'>"+number+": "+eachfriend;
      html +="<i class='fa fa-stop-circle' style='font-size:20px;color:red;'></i>";
    }
     html +="</a></li>";
    $("#all ul").append(html);

    }//success
  });//$ajax
}//getstreamingdata function


for (var i=0;i<friends.length;i++) {
  console.log(i);
  console.log(friends[i]);
  getStreamingData(friends[i], i);
} 

//Same as for loop above, but using forEach. This produces the same results.
/*
var i=0;
friends.forEach(function(friend) { 
   getStreamingData(friend, i);
   i++;
});    
  */

  var a = 4;//testing console output
  console.log(a);
  console.log("why is this showing up before the getStreamingData function's console output?");
  console.log("but it's showing up after the console.log(i) and console.lg(friends[i]) output? So this section is interupting the for loop above");
  console.log(" and why is the for loop out of order and repeating itself?");

 });//doc ready
K Hutch
  • 113
  • 2
  • 3
  • 13

1 Answers1

0

You are doing an asynchronous task in your loop. You should not expect those async tasks finish in the order that they have started.

The function getStreamingData is the one that I'm talking about.

Related: Asynchronous for cycle in JavaScript

This is one snippet that I wrote long time ago and I'm still using it in small projects. However there are many libraries out there which do the same plus many more.

Array.prototype.forEachAsync = function (cb, end) {
    var _this = this;
    setTimeout(function () {
        var index = 0;
        var next = function () {
            if (this.burned) return;
            this.burned = true;
            index++;
            if (index >= _this.length) {
                if (end) end();
                return;
            }
            cb(_this[index], next.bind({}));
        }
        if (_this.length == 0) {
            if (end) end();
        }else {
            cb(_this[0], next.bind({}));
        }
    }, 0);
}

It is not a good practice to touch the prototype like this. But just to give you an idea how you can do this ... After that code, you can loop over arrays asynchronously. When you are done with one element, call next.

var array = [1, 2, 3, 4]
array.forEachAsync(function (item, next) {
    // do some async task
    console.log(item + " started");
    setTimeout(function () {
        console.log(item + " done");
        next();
    }, 1000);
}, function () {
    console.log("All done!");
});
Community
  • 1
  • 1
Aᴍɪʀ
  • 7,623
  • 3
  • 38
  • 52