Understanding JavaScript callbacks

Callback functions appear in most JavaScript. Unless you're looking at very simple code, the chances are it uses callbacks. They can be a little tricky to get your head round at first, but they're such a key feature of the language that understanding them is important.

First-class functions

To grasp callbacks, you first have to understand that functions in JavaScript are objects. This means they can be stored in variables, passed as arguments to functions, created within functions, and returned from functions - just like any other object can. Because we can treat them like this, we say that they are first-class objects.

Consider the following example, in which callback is a function that we're going to pass as a parameter.

// Define a function with callback as a parameter
var sumNumbers = function(num1, num2, callback){
  // Add the first two parameters
  var result = num1 + num2;
  // Call the callback function
  // passing result as a parameter
  callback(result);
}

At this point, you might be wondering what's going on with callback. We've defined it as the third parameter, and called it inside the sumNumbers function, but it's not really doing anything, is it? It doesn't look like a function.

Well...

// Call the sumNumbers function
sumNumbers(2, 4, function(number){
  console.log("Yay, callback called! And the result was " + number);
});

See? The third parameter, defined earlier as callback, is in fact a function. We're passing it here as an anonymous function (that is, a function without a name), but it's worth mentioning that we could just as easily pass a named function too - there's no difference. Writing it inline like this just makes for slightly shorter code examples.

To recap, we've seen two things so far: a function calling another function (sumNumbers calling callback) and a function being passed into another function as a parameter.

So we can define a callback function as:

A function that isn't immediately executed, but instead called back at a point that's convenient to us inside its containing function's body.

Asynchronous functions

So what are callback functions good for? Surely we're just over-complicating this trivial example, right? Well yes, you'd be correct in suspecting that a callback isn't strictly necessary for the process of adding two numbers together.

But what about a more complex example?

Without callbacks, functions just get called, in order, and return some value.

What if we wanted to change that order? Say, to make sure some other process happened before a particular function got called? That's known as an asynchronous operation. They're really useful for situations where things take a while to finish, because it means we don't have to make the browser wait around for some function to return a value.

This is the core idea behind AJAX; a way to make requests to the server directly from the JavaScript running in your browser, so you can update the content of certain elements without reloading the whole page.

Let's look at callbacks in the context of an AJAX request using jQuery:

$(function(){
  var getData = function(item, callback){
    // Begin AJAX request
    $.ajax({
      url: "/some/path/" + item,
      method: "GET",
      success: function(data){
        // Call callback function passing response as a parameter
        callback(data);
      }
    });
  };
  // Append response onto relevant element
  var appendItem = function(data){
    $("element").append(data);
  };
  getData("item", appendItem);
})

So, AJAX is a common real-world example of where using callbacks to call functions asynchronously can come in really handy.