Skip to main content

Command Palette

Search for a command to run...

Callbacks in JavaScript: Why They Exist

Published
4 min read
Callbacks in JavaScript: Why They Exist

When you first learn JavaScript, functions feel simple: you call them, they run, and they return a result.

But as soon as you start dealing with real-world tasks—like fetching data from a server or reading files—you’ll notice something different. Not everything happens immediately. Some tasks take time.

This is where callbacks come into the picture.

To understand callbacks properly, we need to start with a simple idea.


Functions Are Values in JavaScript

In JavaScript, functions are not just blocks of code. They are values, just like numbers or strings.

This means you can:

  • Store them in variables

  • Pass them to other functions

  • Return them from functions

Example:

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

let sayHello = greet;

sayHello();

Here, the function is treated like a value and assigned to a variable.

This ability is what makes callbacks possible.


What a Callback Function Is

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

Example:

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

function done() {
  console.log("Done processing");
}

processUser("Alex", done);

Output:

Processing user: Alex
Done processing

Here:

  • done is passed as an argument

  • processUser calls it later

  • So done is a callback function


Passing Functions as Arguments

Let’s simplify it even more.

function sayHi() {
  console.log("Hi!");
}

function execute(func) {
  func();
}

execute(sayHi);

Instead of passing data, we are passing behavior.

This is powerful because it allows one function to decide when and how another function should run.


Why Callbacks Are Used in Asynchronous Programming

Now comes the real reason callbacks exist.

Some operations in JavaScript take time:

  • Fetching data from an API

  • Reading a file

  • Waiting for user input

We don’t want the program to stop while waiting. Instead, we let the task run in the background and tell JavaScript:

“When you're done, run this function.”

That function is the callback.


Example: Simulating a Delay

console.log("Start");

setTimeout(function () {
  console.log("This runs later");
}, 2000);

console.log("End");

Output:

Start
End
This runs later

Explanation:

  • setTimeout waits 2 seconds

  • Then it runs the callback function

  • Meanwhile, the rest of the code continues

This is asynchronous programming.


Callback Usage in Common Scenarios

Callbacks are used in many real-world situations.


1. Timers

setTimeout(() => {
  console.log("Executed after delay");
}, 1000);

2. Event Handling

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

The function runs only when the event happens.


3. Data Processing

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

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

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

Here, add is passed as a callback.


The Problem with Callback Nesting

Callbacks are useful, but they can become difficult to manage when nested.

Consider this:

doTask1(function () {
  doTask2(function () {
    doTask3(function () {
      console.log("All tasks done");
    });
  });
});

This structure starts to look messy and hard to read.

This is often called callback nesting or informally, callback hell.

Problems include:

  • Hard to read

  • Difficult to debug

  • Difficult to maintain

As programs grow, deeply nested callbacks can make code confusing.


Thinking About Callbacks

To understand callbacks clearly, remember this:

  • A callback is just a function

  • It is passed into another function

  • It runs later, not immediately

The key idea is:

“Run this function after something else finishes.”

This simple concept powers a large part of JavaScript’s asynchronous behavior.


Final Thoughts

Callbacks are one of the foundational concepts in JavaScript. They allow functions to be flexible and enable asynchronous programming without blocking execution.

While they can become messy when overused, understanding callbacks is essential before moving on to modern alternatives like promises and async/await.

If you can understand how callbacks work—especially how and why they are used—you’ll have a much stronger grasp of how JavaScript handles real-world tasks behind the scenes.