-1

I'm a bit confused on how to create and use callback functions when working with async requests. All the examples online like to use a SetTimeout function to mimic an async function but I want an example that just uses a real world API.

I have an async function that takes a zip code and returns a JSON like this:

{
   "post code": "90210",
   "country": "United States",
   "country abbreviation": "US",
   "places": [
       {
           "place name": "Beverly Hills",
           "longitude": "-118.4065",
           "state": "California",
           "state abbreviation": "CA",
           "latitude": "34.0901"
       }
   ]
} 

Here are the functions. The async function goes to an API and returns the JSON above.

The sync function simply takes the JSON and returns the city string in UpperCase.

// Async Function
    var returnLocationInfoByZip = function(zip){
        var client = new XMLHttpRequest();
        var response;
        client.open("GET", "http://api.zippopotam.us/us/" + zip, true);
        client.onreadystatechange = function() {
            if(client.readyState == 4) {
                response = client.responseText;
                return response;
            };
        };
        client.send();
    };

// Sync Function
    var cityToUpperCase = function(responseObject){
        var city = responseObject.places[0]["place name"];
        return city.toUpperCase();
    };

The following code flow doesn't work because I'm not utilizing callbacks. What would be the cleanest-looking way to execute these functions so I could get the desired console log of the city name in all UpperCase?

    // Obviously doesn't work

    var zip = "94043";
    var responseObject = returnLocationInfoByZip(zip);

    //Here I would like to console log the uppercase city name
    var cityInUpperCase = cityToUpperCase(responseObject);
    console.log(cityInUpperCase);

EDIT: Bah, looks like this might have an answer: How do I return the response from an asynchronous call?

I'd still be interested to know how to do it with this particular example of mine though.

Community
  • 1
  • 1
fuzzybabybunny
  • 5,146
  • 6
  • 32
  • 58

1 Answers1

1

You have to pass the sync function (cityToUpperCase) as a parameter to the async function (returnLocationInfoByZip) which will invoke it when onreadystatechange is called:

var returnLocationInfoByZip = function(zip, callback){
    ...
    client.onreadystatechange = function() {
        if(client.readyState == 4) {
            response = client.responseText;
            callback(JSON.parse(response));
        };
    };
    ...
}

var cityToUpperCase = function(responseObject){
    ...
};

...
returnLocationInfoByZip(zip, function(responseObject){
    console.log(cityToUpperCase(responseObject));
});
hindmost
  • 7,125
  • 3
  • 27
  • 39
  • `responseObject` will be undefined. – Artyom Neustroev Oct 28 '14 at 08:53
  • What the... why does the alert on line 10 not work? http://jsfiddle.net/8Lr8hx40/1/ – fuzzybabybunny Oct 28 '14 at 09:31
  • @fuzzybabybunny No `responseObject` is defined, but it is a JSON string which should be converted to object (by `JSON.parse`). See updated answer – hindmost Oct 28 '14 at 09:31
  • Ok, here's an updated fiddle with some notes towards the bottom of the code: http://jsfiddle.net/8Lr8hx40/2/ - so this was what I was worried about. The code originally runs synchronously until it branches into an async branch and a sync branch. If you have any functions that depend on the output of the async branch, they must be forever run in that async branch, which could get very messy-looking, right? What if you wanted to return the result of an async call back into the regular synchronouse flow of your code? – fuzzybabybunny Oct 28 '14 at 09:50