Skip to main content

Command Palette

Search for a command to run...

Callbacks in JavaScript: Why They Exist

Updated
5 min read
Callbacks in JavaScript: Why They Exist

JavaScript is a language where functions are extremely powerful.

In JavaScript:

  • Functions can be stored in variables

  • Functions can be passed as arguments

  • Functions can be returned from other functions

This flexibility allows us to use something called callbacks.

Callbacks are one of the most important concepts in JavaScript, especially in asynchronous programming.

In this article, we’ll learn:

  • What a callback function is

  • Why callbacks are used

  • Passing functions as arguments

  • Real-world callback usage

  • Problems with nested callbacks

Let’s begin with the basics.


Functions as Values in JavaScript

In JavaScript, functions behave like normal values.

We can store them inside variables.

Example:

const greet = function() {
  console.log("Hello");
};

greet();

Output:

Hello

Since functions are values, we can also pass them into other functions.

This is where callbacks begin.


What Is a Callback Function?

A callback is simply:

A function passed into another function

Example:

function greet(name, callback) {
  console.log("Hello " + name);

  callback();
}

function sayBye() {
  console.log("Goodbye");
}

greet("Rahul", sayBye);

Output:

Hello Rahul
Goodbye

Here:

  • sayBye is passed as an argument

  • sayBye is the callback function


Understanding the Flow

greet()
   ↓
Print greeting
   ↓
Execute callback()

The callback runs after the main task completes.


Why Do Callbacks Exist?

Callbacks exist because sometimes we want code to run:

✅ Later
✅ After another task finishes
✅ Only when something happens

Examples include:

  • Reading files

  • API requests

  • Button clicks

  • Timers

Callbacks allow JavaScript to handle these situations.


Passing Functions as Arguments

Let’s look at another simple example.

Example:

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

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

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

Output:

5

Here:

  • add is passed as an argument

  • calculate executes the callback function

This makes code more flexible and reusable.


Real-World Callback Example

Imagine ordering food online.

Flow:

Place Order
    ↓
Wait for Food
    ↓
Food Delivered
    ↓
Receive Notification

The notification happens only after delivery finishes.

Callbacks work similarly in programming.


Callback Example with setTimeout

Example:

console.log("Start");

setTimeout(() => {
  console.log("Task Completed");
}, 2000);

console.log("End");

Output:

Start
End
Task Completed

What Happened Here?

Start runs first
      ↓
Timer starts
      ↓
JS continues execution
      ↓
End prints
      ↓
After 2 seconds callback executes

This is asynchronous behavior.


Why Callbacks Are Important in Async Programming

Some operations take time.

Examples:

  • Fetching data from servers

  • Reading files

  • Database queries

JavaScript does not want to stop the entire program while waiting.

Instead:

Start task
Continue other work
Run callback when task finishes

This makes applications faster and responsive.


Callback Usage in Common Scenarios

Callbacks are used in many places.


Event Handling

Example:

button.addEventListener("click", function() {
  console.log("Button clicked");
});

The callback runs only when the button is clicked.


Timers

Example:

setTimeout(() => {
  console.log("Hello after 2 seconds");
}, 2000);

Array Methods

Example:

const numbers = [1, 2, 3];

numbers.forEach(function(num) {
  console.log(num);
});

The function inside forEach() is also a callback.


Callback Flow Diagram

Main Function
      ↓
Receives Callback
      ↓
Performs Task
      ↓
Executes Callback

The Problem with Nested Callbacks

Callbacks are useful, but deeply nested callbacks can become difficult to read.

Example:

loginUser(function(user) {
  getPosts(user, function(posts) {
    getComments(posts, function(comments) {
      console.log(comments);
    });
  });
});

This structure becomes messy quickly.


Callback Nesting Visualization

Task 1
  ↓
Task 2
   ↓
Task 3
    ↓
Task 4

As nesting increases:

  • Code becomes harder to read

  • Debugging becomes difficult

  • Maintenance becomes harder

This problem is commonly called:

Callback Hell

Why Callback Hell Is Problematic

Problems include:

❌ Deep nesting
❌ Poor readability
❌ Hard debugging
❌ Difficult maintenance

This is one reason Promises and async/await were introduced later.


Simple Callback vs Nested Callback

Simple Callback

sayHello(callback);

Easy to understand.


Nested Callback

task1(() => {
  task2(() => {
    task3(() => {
      task4(() => {});
    });
  });
});

Much harder to manage.


Practice Assignment

Try these exercises yourself.


1. Create a Callback Function

Write a function that:

  • prints a message

  • executes a callback afterward


2. Use setTimeout

Create a timer that prints:

"Task Finished"

after 3 seconds.


3. Use a Callback with Arrays

Use:

forEach()

to print array elements.


4. Observe Callback Flow

Try adding multiple console.log() statements to understand execution order.

This helps build asynchronous thinking.


Final Thoughts

Callbacks are one of the foundations of JavaScript.

They allow JavaScript to:

  • Handle asynchronous tasks

  • Execute code later

  • Respond to events

  • Build dynamic applications

The key idea is simple:

A callback is a function passed into another function to run later.

Although nested callbacks can become messy, understanding callbacks is extremely important because they form the foundation for:

  • Promises

  • async/await

  • Event-driven programming

Mastering callbacks will make learning modern asynchronous JavaScript much easier.


And now, you know what Callbacks in JavaScript are and why they exist.

If you have any doubt or want to connect, feel free to drop a comment — I’d be happy to help.

Thanks for reading, and see you in the next blog!

Peace ✌️ and Happy Learning!