DEV Community

Michael F
Michael F

Posted on • Edited on

Asynchronous JavaScript 2: Callbacks

This is part two of an ongoing series on basic asynchronous operations for JavaScript. If you haven't checked out my first article go check it out it serves as a great introduction into the reason behind why understanding asynchronous techniques are so important to us as JavaScript Developers.

The reason why we are covering callbacks today is because prior to the release of ES6 and ES7, callback functions were one of the only ways to handle asynchronous operations. ES6 and ES7 gave us promises and async/await syntax, which is what most API's utilize today. So it is incredibly important to understand how callback functions work and what they are used for in this context.

A callback function is simply a function that gets passed into another function as a argument. And they are generally used to have better control over the execution sequence. Say if you wanted a function retrieve some data and another function to output the data.


/** 
this function takes in whatever callback you want, 
prompts a user for input and runs the callback with
user input as an argument
*/
function processUserInput(callback) {
  const someText = prompt("Enter in some text: ");
  callback(someText);
}

//call the function and pass in the callback
processUserInput(function(name) {
  console.log(`Hello, ${name}`);
});
Enter fullscreen mode Exit fullscreen mode

In this example we are defining a function that takes in any callback function that you want. It then prompts the user for input. After the input is collected from the user, it is then passed into the callback function to be alerted to the screen.

This, at its most basic, is how callbacks are used. It's that simple. They are just a way of controlling execution sequence.

In the below example you will see another basic example of how callback functions could be used.

callbacks.js

//start by defining a function that outputs a string passed to it. 
function displayMsg(msg){
  console.log(msg);
}

//ok now write a driver function that takes in a callback.
function mainFunction(callback){

    //pass a string into the callback
    const myMsg = "this is a string passed into the callback"
    callback(myMsg);   
}

//now you can pass in the function you defined at the beginning
mainFunction(displayMsg);

//or you can just  define a function to run instead. 
mainFunction(function(msg){
    console.log(msg);
})

Enter fullscreen mode Exit fullscreen mode

Output:

dev@localhost$node callbacks.js
this is a string passed into the callback
this is a string passed into the callback
Enter fullscreen mode Exit fullscreen mode

This is a simple example.

It is important to note that using callbacks in this way is best for simple examples only. Callbacks have a way of making code difficult to read and even worse to debug when you find yourself buried 3 functions deep in the execution stack trying to figure out which callback on which line of code isn't working right.

For instance. Say we were building a house. First we get materials, then we build the framing, then finish the interior, then move in the house.

const buildHouse = (callback) => {
  getMaterials(function (materials) {
    buildFraming(materials, function (finishedFraming) {
      finishInterior(function (finishedInterior) {
        moveIn(finishedFraming, finishedInterior, function (house) {
          callback(house);
        });
      });
    });
  });
};

Enter fullscreen mode Exit fullscreen mode

It doesn't take long for a program to become difficult to read.
Thankfully there is a solution. In JavaScript we can implement asynchronous behavior through the use of Promises and Async/Await. Coming up in the next article.

Top comments (0)