Problem with Twitch App

The problem you’re running into is that you’re running asynchronous code and expecting synchronous results. This can be one of the most confusing aspects of programming. What’s happening is that you’ve got two different calls to the server, and two different callback functions that each execute when the server responds. From the way it’s written, you’d expect the code to run thusly:

  • firstAjaxFunction();
  • firstAjaxCallback();
  • secondAjaxFunction();
  • secondAjaxCallback();

However, that’s not the case. Callbacks do not block, meaning that other code can run while we’re waiting for the server response. The reality is that your code could be executed like this

  • firstAjaxFunction();
  • secondAjaxFunction();
  • secondAjaxCallback();
  • firstAjaxCallback();

or

  • firstAjaxFunction();
  • secondAjaxFunction();
  • firstAjaxCallback();
  • secondAjaxCallback();

And that’s just per username. These four functions are run per username, and the same caveats apply to the order. What’s happening is more like this:

  • firstAjaxFunction(“brunofin”);
  • secondAjaxFunction(“brunofin”);
  • firstAjaxFunction(“FreeCodeCamp”);
  • secondAjaxFunction(“FreeCodeCamp”);
    // ... two seconds later
  • firstAjaxCallback(“brunofin”);
  • firstAjaxCallback(“FreeCodeCamp”);
  • secondAjaxCallback(“brunofin”);
  • secondAjaxCallback(“FreeCodeCamp”);

By the time the last callback has fired, the variables url, status, and name have all changed. In fact, by the time the first callback has fired, the forEach loop has executed and the variable name has changed, which is why everyone is ‘brunofin’.

There are a number of ways to fix this. The best (for now) is to use promises. My least favorite option would be to create a closure for each success callback, and call the second AJAX function inside the callback for the first.

 $.ajax({
      type: 'GET',
      //etc...,
      success: (function() {
        var currentName = name;
        var currentUrl = url;
        return function(data) {
              console.log(data);
              if (data.stream === null) {
                status = "Offline";
              } else {
                status = "Online";
              }

              $.ajax({
                 type: 'GET',
                 //etc...
                 success: function(data) {
                    //stuff
                 }
                });
            }
      }())
  })

I genuinely hate this option and strongly encourage you to use promises. Youtube will have some video tutorials on the subject, though I can’t recommend any one, but also look at the documentation I linked above. You’re going to want to make use of Promise.all(), which is the best thing since unicorn magic.

2 Likes