1

I am trying to return a result from an asynchronous function in Javascript.

I have seen this question: How do I return the response from an asynchronous call?, and I am trying to implement the callback solution, but something is wrong.

This is my code:

function getLocation(callback){
    var lat;
    var long;
    if (navigator.geolocation) {
        navigator.geolocation.getCurrentPosition(function(position)
                {
                    lat = position.coords.latitude;
                    long = position.coords.longitude;
                }, function()
                {
                    console.log('Please enable geolocation in your browser.');
                });
    } else {
        alert('It seems like geolocation is not enabled in your browser.');
    }
var res = {
        "lat": lat,
        "long": long
};
callback(res);
}

function getEventNearYou(){
    var list = [];
    getLocation(function(obj){
        var lat = obj.lat;
        var long = obj.long;
        $.ajax({
                url : 'http://www.skiddle.com/api/v1/events/search/?api_key=myapikey' + '&latitude=' + lat + '&longitude=' + long + '&radius=800&eventcode=LIVE&order=distance&description=1',
                type : "GET",
                async : false,
                success : function(response) {
                        $(response).find("results").each(function() {
                        var el = $(this);
                        var obj = {
                                    "eventname" : el.find("eventname").text(),
                                    "imageurl" : el.find("imageurl").text(),
                                  }
                        list.push(obj);
                        });
                        } 
                });
        return list;
    });
}

Basically, I want to find my current location, and create a HTTP get request to www.skiddle.com to retrieve events near that location.

This is how I call the function:

var x = getEventNearYou();

but I seem to have made a mistake, since I am getting the bad request error (lat and long are undefined).

  • What is `obj` that is parameter to `getLocation`? What is purpose of redefining `obj` within `success`? – guest271314 Oct 01 '17 at 15:16
  • seems like `navigator.geolocation.getCurrentPosition` have callback function. So before you get that callback run `callback(res);` will executed. That is why you will not get `lat` and `long` values. – dwij Oct 01 '17 at 15:18
  • @dwij What would be the recommended way to deal with this? – user2921579 Oct 01 '17 at 15:24
  • try `callback(res);` inside `navigator.geolocation.getCurrentPosition` success function. Also you need to push the `res` variable assignment to that success function – dwij Oct 01 '17 at 15:25
  • @dwij That helped with the request, which is now fine, but the list of objects I want to return from the `getEventNearYou()` is still undefined. – user2921579 Oct 01 '17 at 15:33

2 Answers2

2

You're using callbacks in a way that undermines their usefulness. You're still writing your code in a synchronous style. You should continue to reference: How do I return the response from an asynchronous call?

In the mean time, I'll restructure your code to show how it's done.

  1. As a rule of thumb, if any of the code inside a function uses callbacks, that outer function also needs to accept a callback as a parameter.

  2. If a variable is given a value inside a callback function, it won't be defined outside of the callback function (because asynchronous code always runs after synchronous code).

  3. Don't use async: false

function getLocation(callback){
    if (navigator.geolocation) {
        navigator.geolocation.getCurrentPosition(function (position) {
            var lat = position.coords.latitude;
            var long = position.coords.longitude;
            var res = { "lat": lat, "long": long }; 
            callback(res);
        }, function() {
            console.log('Please enable geolocation in your browser.');
        });
    } else {
        alert('It seems like geolocation is not enabled in your browser.');
    }
}

function getEventNearYou(callback) {
    getLocation(function(pos){
        var lat = pos.lat;
        var long = pos.long;
        $.ajax({
            url: 'http://www.skiddle.com/api/v1/events/search/?api_key=myapikey' + '&latitude=' + lat + '&longitude=' + long + '&radius=800&eventcode=LIVE&order=distance&description=1',
            type: "GET",
            success: function(response) {
                var list = [];
                $(response).find("results").each(function() {
                    var el = $(this);
                    var obj = {
                        "eventname": el.find("eventname").text(),
                        "imageurl" : el.find("imageurl").text(),
                    };
                    list.push(obj);
                });
                callback(list);
            } 
        });
    });
}

Then call getEventNearYou using a callback function:

getEventNearYou(function (events) {
    // code which relies on `events` can be called from here
});
4castle
  • 32,613
  • 11
  • 69
  • 106
1

Just adding a bit more explanation to 4castle's excellent answer. In the code you wrote, when your getLocation() function is called in Javascript, this is what will happen:

  1. var lat and var long are instantiated with values of undefined.
  2. navigator.geolocation.getCurrentPosition() is called, which takes a long time to complete.
  3. In the meantime, Javascript looks for something else to do and moves to the next lines in your function.
  4. The res object is instantiated with the current undefined values of lat and long. That is, res is: { "lat": undefined, "long": undefined }
  5. The callback function is called on res. This means callback is called with undefined values for lat and long.
  6. navigator.geolocation.getCurrentPosition() finally finishes what it was doing and assigns values to lat and long, but by now it is too late because your callback function was already called on the undefined values.

In 4castle's revised code, steps 4-5 are put inside an anonymous callback function to navigator.geolocation.getCurrentPosition(), which means these lines won't be executed until getCurrentPosition() is finished getting the position.

boylingpoynt
  • 219
  • 2
  • 5