Wait for an asynchronus variable

Hello fellow camper.

I was working on my twitch api , and i’m faced to a problem I have no idea how to solve :

I’m using a variable to stock all the JSON awnser from the api, but since it’s an asynchronus event, I can’t manage to fire the function on document.ready : I get an error telling me how the variables are undefined.

Note that is I use a button to fire the api function rather than the document.ready function it works perfectly.

Here’s what the part of my code that poses problem looks like :

var lives = ["nat_ali","krayn_live","streamerhouse","merry","freecodecamp"];
var streams = lives.map((val) => {
  return $.getJSON("https://wind-bow.glitch.me/twitch-api/streams/"+val+"?callback=?");
});
var users = lives.map((val) => {
  return $.getJSON("https://wind-bow.glitch.me/twitch-api/users/"+val+"?callback=?")
});

$(document).ready(function(){
    $.when(streams).then(getStreams(getUsers) );
});

link to the codepen : https://codepen.io/Hadrienallemon/pen/ddBOxB
(you can see if you click the test button at the bottom on the page how the api call works perfectly ? )

would anyone have any idea about how to solve this ?

Thanks in advance !

$.when( ) accepts a deferred object. You’re putting an array of deferred objects. What you want to do is everytime $.getJSON is finished, you use .done or .then to add an element to the page.

@elisecode247 is right that your use of $.when is the cause of your problem, but I wanted to figure out why it works at all. It took me a while, and ultimately I got the answer.

First, it’s important to understand that an array of promises will begin execution before the array is used. This is what happens when you map the array of promises:

var streams = lives.map(val => {
  return $.getJSON(
    "https://wind-bow.glitch.me/twitch-api/streams/" + val + "?callback=?"
  );
});

Second, when you call $.when with something other than a deferred object or promise, the following then is immediately invoked and whatever you passed to when becomes the parameter for then's callback.

$.when("This is not a promise")
    .then(result => console.log(result)); // "This is not a promise"

If you pass it an array of promises, those promises are still going to make their requests, but when isn’t going to wait for a single one of them to be done before calling then. Even though those promises are actually fetching data just as you expect, they’re not going to be finished before when calls then. Thus, when the page first loads, there’s no response data to work with and you get an error for trying to get the responseJSON property. By the time you press the button, all of the promises have response values and your code is able to iterate through them.

Note that when when passes its finished promises, they are passed as individual parameters to your then callback. This would mean you should expect 5 arrays of objects, since each getJSON function returns three parameters each.

$.when(...streams) // use the spread operator to turn an array into individual items
    .then(function(first, second, third, fourth, fifth) {
        console.log(first); // [{responseData}, "responseText", {jqueryXHRObject}]
    });

Since when is just passing an array of promises, you’re able to write your code to expect a single array of response data, as you would with Promise.all.

It’s great that you’re using higher order functions and promises, and I can see your thought processes to solve these problems. It may be better if you wrote your code using fetch and Promise.all instead of getJSON and when, though.