Some basic questions about using JS, API's, JSON objects, controlling the flow of program execution

In the examples I see, coders usually put all the manipulations or adressing of the JSON object within the callback function in the API call. However, my instinct, for whatever reason, is to get the JSON object stringified and assigned to a wider scoped variable, so I can use it from functions outside of the callback. Is it unhealthy for me to hate the anonymous callback functions and putting all that code inside the callback function? http://codepen.io/dempseyc/pen/mOXdOR

No, it’s not unhealthy. Readability is important, both for you and for other people who have to work with your code. Writing your callbacks separately can often improve readability, as can breaking so-called “spaghetti code” into smaller functional units.

I learned about this YouTube play list here on the FCC forums - it’s terrific: Modular JavaScript. The series describes some common design patterns. The ‘Revealing Module Pattern’ (video 3 in the play list) is a pattern you’ll see in some frameworks (AngularJS factories and directives, for example). But watch how the author refactors “spaghetti code” into beautifully well-structured code over videos 1 - 3.

Having said all this, remember the A in AJAX: asynchronous! Triggering functionality from callbacks ensures that an AJAX response is available to work with prior to actually working with it. More often than not, your code will completely finish executing before some AJAX response comes back. For example, if you uncomment the HTTP .get() code in your doAPIStuff function, the toHTML() outside the callback will fire before the .get() request is fulfilled. Consequently jsonWeather is undefined at that point in the execution and toHTML() has no data to work with. Consider this simplification:

function doAPIStuff(lat, lon) {
  apiUrlString = "http://api.openweathermap.org/data/2.5/weather?lat=" + lat + "&lon=" + lon + "&units=imperial&appid=blahblahblah";

  $.get(apiUrlString, function (weather) {
    jsonWeather = JSON.stringify(weather);
  });
  
  console.log(jsonWeather); //  >> undefined!
}

It’s undefined because console.log(jsonWeather) fires before the get response arrives and populates jsonWeather.

You need to manipulate the response within the callback, either via spaghetti code or calls to separate functions (or via promises!). In your case, it’s as simple as moving your utility functions inside the callback block. A bit of a refactor…

function doAPIStuff(lat, lon) {

  // collect all api-related ajax stuff here
  api = {
    endpoint: "http://api.openweathermap.org/data/2.5/weather",
    params: {
      lat   : lat,
      lon   : lon,
      units : "imperial",
      appid : "blahblahblahblahblah"
    },
    callback: function(weather) {
      getTheDate(weather);
      toHTML(weather);
    }
  };

  // do the work
  $.get(api.endpoint, api.params, api.callback);
}
1 Like

Thank You so much belcurv! I guess the point is that the simplest way of controlling the flow of execution in this case is to use the callback. I’ll check out that link too.

belcurv’s answer is much more detailed than I could ever hope, but i’ll just share as someone relatively new to the idea of callbacks and asyncrhonous programming that while it’s tempoting to want everything to be global or wider scope, it can cause really challenging errors, when code runs before data is available to that variable or to a function whcih uses a variable waiting for an asynchronous result.

SO do it, as long as it works. But when it stops working you’ll be pulling your hair out.

I just spent a few hours tonight working on such a thing.

I’m no jQuery expert, but apparently in addition to the traditional callback form, jQuery’s XHR/AJAX methods also return a promise object. See official docs:

jQuery.get(): https://api.jquery.com/jquery.get/
jQuery.ajax(), jqXHR object: https://api.jquery.com/jQuery.ajax/#jqXHR

Promises are pretty sweet, but in this project’s case I think you’re right: the traditional callback form is simpler.