Javascript, Programming

JavaScript Callbacks

JavaScript functions are invoked in the sequence they are called instead of the sequence they are defined.

const locations = [
    { state: "Alabama", city: "Athens" },
    { state: "Alaska", city: "Nome" },
    { state: "Arizona", city: "Kingman" },
    { state: "California", city: "Bakersfield" },

];
//Get location takes 1 seconds to display the locations
function getLocations() {
    setTimeout(()=>{
            let output = "";
            locations.forEach((location, index) => {
                output += `<li>${location.state}, ${location.city}</li>`;
            });
            document.getElementById("location").innerHTML = output;
    }, 1000);
}


function addNewLocation(location) {
    console.log(location);
    setTimeout(()=> {
            locations.push(location);
    }, 2000);
}
getLocations();
addNewLocation({state:"Colorado", city:"Brighton"});

 

The aforementioned example displays the following locations and doesn’t display newly added locations using addNewLocation function

  • Alabama, Athens
  • Alaska, Nome
  • Arizona, Kingman
  • California, Bakersfield

Most of the time, we like to have better control over the execution of the function. For that, we could increase the execution time of getLocations function and decrease the execution time of the addNewLocation function. But the better way to solve the execution order of the functions is using a callback.

A callback is a function that is passed as an argument to another function and is invoked after another function/event is executed.

const locations = [
    { state: "Alabama", city: "Athens" },
    { state: "Alaska", city: "Nome" },
    { state: "Arizona", city: "Kingman" },
    { state: "California", city: "Bakersfield" },

];
function getLocations() {
    setTimeout(()=>{
            let output = "";
            locations.forEach((location, index) => {
                output += `<li>${location.state}, ${location.city}</li>`;
            });
            document.getElementById("location").innerHTML = output;
    }, 1000);
}
function addNewLocation(location, callback) {
    console.log(location);
    setTimeout(()=> {
            locations.push(location);
            callback();
    }, 2000);
}

addNewLocation(
    {state:"Colorado", city:"Brighton"},
 getLocations);

 

In the example above, getLocations is used as a callback function, and is called after  2 seconds right after the new location is pushed in the location list.  Above example displays all the locations including the new location.

  • Alabama, Athens
  • Alaska, Nome
  • Arizona, Kingman
  • California, Bakersfield
  • Colorado, Brighton

Callbacks are useful in asynchronous functions, where one function has to wait for another function (like getting data from the network).

However, callbacks get complicated when the callback itself has to call the function that accept callbacks.

function add1(num, callback) {
  const total = num + 1;
  callback(total);
}

function add2(num, callback) {
  const total = num + 2;
  callback(total);
}

function add3(num, callback) {
  const total = num + 3;
  callback(total);
}

function totalSum() {
    add1(1, total1 => {
    add2(total1, total2 => {
        add3(total2, total3 => {
        console.log(`result: ${total3}`);
      });
    });
  });
}
totalSum();

This is a simple 3-levels code to get the grand total, but there could be a nesting of callbacks. The nesting of callbacks can get hard to understand and debug.

Callbacks were used for a long time until es6 was released or es2015 until when promises were introduced to the JavaScript language and promises give us a more elegant way to handle asynchronous data. Then in es7, the async wait was introduced which deals with the promises in a different way.

Views: 9

Standard