Skip to main content

Command Palette

Search for a command to run...

Callbacks in JavaScript: Why They Exist

Updated
3 min readView as Markdown

JavaScript is widely known for its ability to handle asynchronous operations such as API requests, file reading, and timers. One of the earliest and most fundamental techniques used to handle asynchronous behavior in JavaScript is the callback function.

In this article, we will understand what callbacks are, why they exist, how they work, and the common problems associated with them.

Functions as Values in JavaScript

In JavaScript, functions are first-class citizens. This means functions can be:

  • Assigned to variables

  • Passed as arguments

  • Returned from other functions

Example:

function greet(name) {
  return "Hello " + name;
}

const sayHello = greet;

console.log(sayHello("Parth"));

Here, the function greet is assigned to a variable and used like any other value.

This ability allows JavaScript to pass functions into other functions, which leads to the concept of callbacks.

What Is a Callback Function?

A callback function is a function that is passed as an argument to another function and is executed later.

Example:

function processUser(name, callback) {
  console.log("Processing user...");
  callback(name);
}

function greetUser(name) {
  console.log("Hello " + name);
}

processUser("Parth", greetUser);

Output:

Processing user...
Hello Parth

Flow visualization:

processUser()
   │
   └── callback() executed

Here, greetUser is the callback function.

Passing Functions as Arguments

Because functions are values in JavaScript, they can be passed as parameters.

Example:

function calculate(a, b, operation) {
  return operation(a, b);
}

function add(x, y) {
  return x + y;
}

console.log(calculate(5, 3, add));

Output:

8

Here:

calculate → receives function → executes it

This pattern is very common in JavaScript.

Why Callbacks Are Used in Asynchronous Programming

JavaScript runs on a single-threaded event loop, meaning it executes one task at a time. However, many operations take time, such as:

API requests

File reading

Database queries

Timers

Callbacks allow JavaScript to continue executing other code while waiting for these operations.

Example with setTimeout:

console.log("Start");

setTimeout(function () {

console.log("Task completed");

}, 2000);

console.log("End");

Output:

Start End Task completed

Explanation:

setTimeout schedules callback JavaScript continues execution callback runs later Callback Usage in Common Scenarios

Callbacks are widely used in many JavaScript features.

  1. Event Handling button.addEventListener("click", function () {

console.log("Button clicked");
});

The function runs when the event occurs.

  1. Timers

setTimeout(() => {

console.log("Executed after 2 seconds");

}, 2000);

  1. Array Methods

Many array methods use callbacks.

const numbers = [1, 2, 3];

numbers.forEach(function(num) {

console.log(num);

});

The Problem of Callback Nesting

When multiple asynchronous operations depend on each other, callbacks can become deeply nested. This problem is called callback nesting or callback hell.

Example:

loginUser(function(user) {

getUserPosts(user.id, function(posts)

{ getComments(posts[0], function(comments)

{ console.log(comments);

});

});

});

Visualization:

loginUser

└── getUserPosts

└── getComments

Problems caused by this structure:

Hard to read

Difficult to maintain

Hard to debug

Increased complexity

Because of these problems, modern JavaScript introduced Promises and Async/Await as better alternatives.

How Modern JavaScript Solves Callback Problems

Instead of deep callback nesting, developers now use Promises or Async/Await.

Example using async/await:

async function getCommentsFlow() {

const user = await loginUser();

const posts = await getUserPosts(user.id);

const comments = await getComments(posts[0]);

console.log(comments);

}

This structure is cleaner and easier to read.

Conclusion

Callbacks are one of the most important foundational concepts in JavaScript. They allow functions to be passed as arguments and executed later, which makes asynchronous programming possible.

Although callbacks can sometimes lead to nested and complex code, understanding them is essential before learning modern approaches like Promises and Async/Await.