How callback functions in JavaScript work

I'm building a thing that's not quite finished yet, and it uses the geolocation API to get latitude and longitude. I wanted to put them into an object and use it for calculations.

My first attempt was:

var loc = {
    get_latlong: function() {
        var self = this,
            update_loc = function(position) {
                self.latitude = position.coords.latitude;
                self.longitude = position.coords.longitude;
            };

        win.navigator.geolocation.getCurrentPosition(update_loc);
    }
};

What I thought this would do was add two properties — latitude and longitude — to the loc object that I could pick up and run with straight away.

It seemed to work because console.log(loc) gave me the object with the two properties added (and their values), but console.log(loc.latitude) was undefined.

I explained my problem on Stack Overflow and got a good answer from Oleg that got me on the road to solving my problem.

It was CBroe's comment on my question that led me to understand how things were working though.

The getCurrentPosition method is asynchronous, and for good reason. Looking up a location can take some time, so we don't want to hold everything up while that happens. I was asking a question that geolocation hadn't answered yet, which is why it always came back undefined.

What I needed was some way to say "get the location then do the calculations," and that is a callback function.

Here's a basic use of a callback function:

// define the function
var some_function = function(arg, callback) {
    // do something here e.g.
    var square = arg * arg;

    callback(square);
};

// call the function
some_function(5, function(param) {
    // do what it says in some_function definition, then do this
    console.log(param);
});

Running that will log 25 to the console.

The easiest way to think of it is to see it in two steps. First of all some_function is called to do it's thing on the number 5, in this case square it.

Next up is the callback function. some_function is expecting a second argument, and it's expecting it to be a function with one parameter — callback(square).

All we need to do is say what the callback does, in this case log the argument it received, square, to the console.

Another way of putting it: the function call is saying "run some_function and do what you have to do, then when you're finished run the anonymous function that has been passed as the second argument, with square as an argument."

In my example I need to wait for the location information to be returned by the geolocation API then pass the loc object to the callback function to perform calculations on the latitude and longitude.

It's subject to change, but right now it looks like:

var loc = {
    get_latlong: function(callback) {
        var self = this,
            update_loc = function(position) {
                self.latitude = position.coords.latitude;
                self.longitude = position.coords.longitude;

                callback(self);
        };

        win.navigator.geolocation.getCurrentPosition(update_loc);
    }
};

loc.get_latlong(function(loc) {
    // loc.latitude and loc.longitude are now available
}

Here are a couple of articles I found useful when trying to get my head round this: