JS/Jquery: Variable-changes in $.getJson-environment get lost outside of it - why?

JS/Jquery: Variable-changes in $.getJson-environment get lost outside of it - why?
0

#1

Heya guys,

I’m currently working on the Twitch API project and though I think I can solve it well, I discovered a for me weird functionality in Javascript/Jquery and want to understand it.

$(document).ready(function() {
	var attr = [];
	$.getJSON('https://wind-bow.gomix.me/twitch-api/channels/monstercat?callback=?', function(json) {	
		attr.push(json.display_name);
		attr.push(json.logo);
		attr.push(json.url); 
	});
	$("#main").html(JSON.stringify(attr));
});

This code should push some attributes from the Twitch API about the channel “monstercat” onto the array attr. The problem is, it always returns an empty array

[]

But if I move the html-command into the .getJSON-function (as below), it works:

$(document).ready(function() {
	var attr = [];
	$.getJSON('https://wind-bow.gomix.me/twitch-api/channels/monstercat?callback=?', function(json) {	
		attr.push(json.display_name);
		attr.push(json.logo);
		attr.push(json.url); 
		$("#main").html(JSON.stringify(attr));
	});
});


This code returns the desired array

[“Monstercat”,“https://static-cdn.jtvnw.net/jtv_user_pictures/monstercat-profile_image-3e109d75f8413319-300x300.jpeg","https://www.twitch.tv/monstercat”]

So why does it do that? The changes to the array attr should be permanent, no? Or does it reset attr again? Will be happy about every feedback. :slight_smile:

Ps: I minimalized my code for this post and this is not my code for the solution of the project. I’m just interested to understand this seemingly weird mechanic.


Using freecodecamp's weather api
Show local weather - open weather API wont run in codepen
#2

Welcome to the wonders of asynchronous code :sparkle:

Before diving in you have to understand that javascript wait for no man!

What does that means in practice?

Look at this example:

function f() {
  setTimeout(function() {
    console.log('I will come 500ms late')
  }, 500);

  console.log(`I won't wait`)
}

f()
// I won't wait
// I will come 500ms late

Why exactly the second functions is printed before?
Because javascript won’t wait for the timeout to finish before passing to next function, unless specifically instructed to.

What does it means for your code?

Your API request is, exactly as my timeout, since it has to wait for the data to travel across the land of the internet.

What happens in your first cod is that

$("#main").html(JSON.stringify(attr));

gets executed before the data is actually even came back, hence the empty array.

On the second case however, being in the same scope as your asynchronous request, it gets executed after the data has actually came back.

Make sense?
Happy coding :smile:


#3

Absolutely beautifully written response! Thank you!


#4

Thanks so much for the reply, Marmiz! That seems very messy, I feel. Is there any way that I can convince Javascript to wait for the answer before continuing with the code? (except for a timer)


#5

JS won’t wait. Don’t try to find a way to make it wait. Other languages are synchronous and will wait, but JS is asynchronous and won’t wait.

This makes sense since JS has to deal with the web. Can you imagine if the code waited every time you called an api or tried to download something? Asynchronous is much better for what JS tries to do.

Yes, it is a pain sometimes. But don’t fight it, find out how to work with it. Learn to think that way. This is going to come up a lot in JS. Did I say “a lot”? I meant A LOT!

The easiest way to handle it is to put all the code that needs to know attr inside that callback function:

$(document).ready(function() {
  var attr = [];
  $.getJSON('https://wind-bow.gomix.me/twitch-api/channels/monstercat?callback=?', function(json) {	
    attr.push(json.display_name);
    attr.push(json.logo);
    attr.push(json.url); 

    $("#main").html(JSON.stringify(attr));

    // any other code needing attr

    // you can call outside functions that need attr too

    someFunc(attr)
  });
});

There are other ways to handle it, but this is the simplest and the callback function is a pattern that is really basic to JS.

Seriously, you’ll drive yourself crazy if you try to fight it. Just drink the asynchronous koolaid. Yeah, it’s a pain in the but sometimes, but it can also be incredibly powerful for a lot of web based things that JS has to do.


#6

Just to clarify, mine was an explanation on why your code behave like that, and not how to fix it.

The timeout was just an example that you can try for yourself to better help you visualize how JS code gets executed when some actions comes later than others.

There’s a constructor that aims to make writing asynchronous code easier, but definitely requires a good understanding of javascipt: Promise