Stuck on twitch tv project for 2 weeks


#1

I’ve sunk 2 weeks into trying to get my twitch tv app to display the online and offline status of users but can still not figure out how to display them separately. That is, I understand conceptually what I want to do, and I’ve coded it as such, but its still not working. My codepen is here: https://codepen.io/Crimson_Macaw/pen/jwoYEN?editors=1111

I first search through https://api.twitch.tv/kraken/streams/ to get the online users by checking if their status !== null. Then on line 33 I’ve written a line of code:

if ($("#mainContainer").find('#' + users[i]).length){
      continue;
    }else{ 

which is supposed to check my html and see if it contains the names of those previously searched for online users, and if it does, then the subsequent Ajax call to https://api.twitch.tv/kraken/channels/ skips over those names. But it’s not doing that at all and is simply providing me with the names of both the online and offline users. I’ve tried different solutions to this issue but then I’m running into other problems. I’m quite sure that my approach should work because I’ve seen it working in other peoples code.

If someone could help me out with this I would greatly appreciate it.


#2

I think you have the right idea, you are just not able to do it with your current JavaScript skills. The issue is that you can’t (normally) do AJAX requests in for loops. For loops are synchronous - AJAX is asynchronous. That means that your first for loop finishes and starts the second for loop before the data is received in the first for loop. Let me illustrate it:

for loop 1 => calls data for every user
for loop 2 => calls data

-- several milliseconds later --

<= data from for loop 1 is received and placed on page
<= data from for loop 2 is received and placed on page

Thus, the if statement in your second for loop is not working, because the data in for loop 1 has not been received yet.

This is a common issue to newcomers (I struggled with it forever last year) and is still a tricky and sore spot for many developers. Fortunately new features to JavaScript are being added and tweaked as I write this, and dealing with this asynchronous code keeps getting simpler.

I would start by learning some more about async JS, and then you will be able to approach this problem with not just the right idea, but also the right JS theory knowledge to make it work.

Here’s some things you can start with:


https://www.thenetninja.co.uk/courses/asynchronous-javascript-tutorial


#3

If you put the following console.log() statement on the line before the if statement you posted above, you get 0 for each, so the else is never executed. 0 evaluates to false on the if statement, which is why the else is used.

console.log($("#mainContainer").find('#' + users[i]).length);

#4

I guess I’ll scrap this approach and try something else. But I’m 100% certain that this .find command worked in other peoples code.


#5

Would you mind linking to an example?


#6

If I may offer a sort of work around:
I am not using the .find() function, but I have found that my code executes before I would like it to do so. I did however find, as method which allows you delay the running of code by a set amount of time.

setTimeout(function() {
		//Your code here
	}, 3000);

It’s fairly simple to use. I found that running the actual updating of my webpage about 3 seconds (or 3000 milliseconds as demonstrated here) after the initial calls the twitch API, to be rather effective. Of course, your millage may vary with this method, and it isn’t perfect, but for the moment it works for me.

A link to my codepen if you want to see it in action: https://codepen.io/hijerboa/pen/XgLQpd

Hope this helped! :slight_smile:


#7

Trying to write asynchronous code by trial and error can drive one up the wall - better to first read up on the basic concepts


#8

@Hijerboa Thanks for your suggestion. It isn’t particularly elegant, but it at least solves the initial problem I had and does prevent me from having to rewrite the code from the beginning (I was actually planning to just use forEach and go through each name in the array individually). The 3 second delay wasn’t even necessary - 1 second is enough. All in all, it’s a pretty adequate workaround to keep in mind whenever having to make multiple Ajax calls.

@IsaacAbrahamson On line 28 of the following codepen is an example that used the .find approach in a working twitch tv viewer: https://codepen.io/AbdiViklas/pen/PzgRbj?editors=0011
That’s where I got the initial idea from.


#9

Hi Hijerboa,

With no disrespect, using a delay to solve an async problem is a brittle way to solve it. Assume that this was production code, and it was pushed out to the general public and thousands of folks were using it. Then assume that something changed at the server you were pulling data from (which you do not control and will happen), and most replies started taking 3.1 seconds to return. And now your users are all looking at a broken app. We could be extra safe and set it to 5 or even 10 seconds, but then everyone will have to wait 10 seconds before the page updates. Unless you can control and guarantee the maximum delay, this solution always breaks sooner or later, or it becomes very slow as you try to mitigate the unexpected.

The correct way to handle this is to perform all of the processing on the data you receive from async method in the callback function(s) of those async methods. This way, your app updates as soon as it’s possible for it to update. And, if there are any unexpected delays this approach handles it and it all just works. This usually means rendering or updating your UI in the callback routines. It’s not perfect or polished, but you are welcome to look at how I an using callbacks in my project (https://codepen.io/michaelbecker/pen/PbVPBE?editors=0010)

I mention this because I’ve seen lots of folks use timeouts to solve async problems, and they always end up breaking, usually on a Friday afternoon right before you want to go home. I was chasing one just this past week that causes a very expensive commercial shipping product to occasionally not boot. It was coded by an experienced software engineer years ago, and only now has it started to be a problem.

Best regards,
-Mike


#10

Using a timeout does not solve your problem, it simply avoids it. Don’t settle for doing less than your best. Choosing to go an incorrect route instead of rewriting the code correctly may help you pass the challenge and save you time, but in the end, it will waste you more time than learning how to do it correctly now. I assume you are using freeCodeCamp to be able to learn how to program. Why not use an easy project like this to actually learn how to properly handle asynchronous code, instead of hampering your skills just to get by. Learn and understand how callbacks really work. Learn how Promises and Async Functions work. I don’t think rewriting less than 100 lines of code is that big of a pain in the butt. Don’t cheat yourself on learning.


Unfortunately, I can’t compare that for loop code to your previous, because you have now changed it to using the settimeout. If I remember correctly based on my previous answer, you had your ajax call in a for loop structured something like this pseudocode:

var users = []
for (user in users) {
  $.ajax(user) {
    // append data
  }
}

they have it structured like this:

var users = []
$.ajax(users) {
  callback(data) {
    for (user in data) {
      // append data
    }
  }
}

The difference is subtle, but it relies on a proper knowledge of callbacks. Read my first answer. I told you that you can’t do AJAX in for loops, and that your app looked like this:

for loop 1 => calls data for every user
for loop 2 => calls data

-- several milliseconds later --

<= data from for loop 1 is received and placed on page
<= data from for loop 2 is received and placed on page

If I was to draw up this other codepen app the same way, it would look like this:

AJAX request data => call callback function when done
callback function receives data
for loop 1  places data on page
for loop 2 places data on page

In their codepen, they run the for loop after they have received the data, therefore the if statement works. In your codepen, you were running the for loop before you got the data. In your set timeout code, you are using a callback:

setTimeout(yourCode, 3000)

and yourCode is “called back” after 3000 milliseconds. In their codepen, their code is called back after the data has been recieved. Again, the problem is not with your approach, it is with your current understanding of callback functions and asynchronous JavaScript. I can’t stress it enough, you really need to learn how to properly write asynchronous JavaScript, or you will just not get anywhere. You have nothing to lose by watching and reading the links I posted above, its free and you can do it in a couple hours. With just a little bit of study, I think you will be able to not just work around the issue, but actually understand what is going on.


#11

I agree. I’m currently working on making mine work “better” with this sort of thing. Like I said, it was a work around, not an actual solution.


#12

I’ve made another copy of my Twitch project to experiment on: https://codepen.io/Crimson_Macaw/pen/mMVePX however I still can’t get it to work even using promises. I’ve tried all different types and none of them seem to work. I know that the way its set up now is obviously wrong but if someone who knows promises can give me the correct version it should save me a lot of time in random experimentation.


#13

I found an older post from last year where the OP used promises for this project, apparently to some success: [SPOILER] Twitch and promises

I still can’t get mine to work without using setTimeOut and so would be interested in finding out how to successfully use the promises approach.