简体   繁体   中英

Javascript asynchronous function: callback not working

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).

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
});

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.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM