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);
}
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(): jQuery.get() | jQuery API Documentation
jQuery.ajax(), jqXHR object: jQuery.ajax() | jQuery API Documentation
Promises are pretty sweet, but in this projectâs case I think youâre right: the traditional callback form is simpler.