# Callback Functions in JavaScript

You've probably typed something like this and moved on without really thinking about it:

```javascript
setTimeout(function() {
  console.log("hello");
}, 1000);
```

That function you passed inside `setTimeout`?

That's a callback. And once you truly understand what's happening there, a huge chunk of JavaScript events, fetch, promises, array methods, suddenly makes complete sense.

Let's start from the very beginning.

## Functions Are Just Values

Before we even touch callbacks, you need to see something that surprises a lot of beginners.

In JavaScript, a function isn't special. It's just a value like a number, a string, or an object. That means you can store it in a variable, put it in an array, and yes, pass it as an argument to another function.

Watch:

```javascript
// a number stored in a variable
const age = 25;

// a string stored in a variable
const name = "Satpal";

// a function stored in a variable — same idea
const greet = function() {
  console.log("Hello!");
};
```

`greet` is just a variable that holds a function. You can pass it around exactly like you'd pass `age` or `name`. This one idea is the entire foundation of callbacks.

## So What Is a Callback Function?

A callback is simply a function that you pass *into* another function, so that other function can call it later.

That's it. Nothing magical. Just a function being passed as an argument.

```javascript
function doSomething(callback) { 
    console.log("doing the task...");    
    callback(); // calling the function you passed in 
}

function finished() {
  console.log("task complete!");
}


doSomething(finished);

// Output:
// doing the task...
// task complete!
```

![](https://cdn.hashnode.com/uploads/covers/6950d1ca85602739c40abd67/4c488a9a-685b-4c90-8be5-0dd34ccbf913.png align="center")

Notice: we wrote `finished` not `finished()`. When you write `finished()`, you're calling it right then. When you write `finished`, you're passing the function itself handing it over like a recipe card. The other function decides when to cook.

## A Real-World Analogy

Think about ordering food at a restaurant.

You place your order and give the waiter your phone number. You don't stand at the counter waiting. You go sit down. When the food is ready, the kitchen *calls you back*.

Your phone number is the callback. You handed it over and said "call this when the thing is done."

JavaScript works exactly the same way. You hand a function over and say "run this when you're done."

## Passing Functions as Arguments

Let's see this in non-async situations first, because callbacks are not just an async thing.

**Example 1:**

**A simple custom function:**

```javascript
function greetUser(name, callback) {
  const message = "Hello, " + name + "!";
  callback(message); // passes the message to your callback
}

greetUser("Priya", function(msg) {
  console.log(msg); // Hello, Priya!
});
```

**Example 2 — you already use callbacks with array methods:**

```javascript
const numbers = [1, 2, 3, 4, 5];

// the function you pass to .filter() is a callback
const evens = numbers.filter(function(num) {
  return num % 2 === 0;
});

console.log(evens); // [2, 4]
```

Every time you use `.map()`, `.filter()`, `.forEach()`, `.sort()` — you are already writing callbacks. Every day. You just might not have called them that.

## Why callbacks exist

Here's the real reason callbacks are everywhere. JavaScript runs in a single thread. That means it can only do one thing at a time. When it hits something slow — a network request, a file read, a timer it can't just freeze and wait. The whole page would lock up.

So instead, JavaScript says: *"I'll start this task, then come back to the rest of the code. When the slow thing finishes, call this function."*

```javascript
console.log("1. Start");

setTimeout(function() {
  console.log("2. This runs after 2 seconds");
}, 2000);

console.log("3. This runs immediately");

// Output:
// 1. Start
// 3. This runs immediately
// 2. This runs after 2 seconds   ← came back later
```

JavaScript didn't pause at the `setTimeout`. It registered your callback, moved on, and came back when the timer expired. That's the whole idea.

## Callbacks in common scenarios

You see this pattern everywhere once you know what to look for.

**Reading a file (Node.js):**

```javascript
fs.readFile("data.txt", function(error, content) {
  if (error) {
    console.log("Something went wrong");
    return;
  }
  console.log(content);
});
```

**Listening for a button click:**

```javascript
button.addEventListener("click", function() {
  console.log("button was clicked!");
});
```

**Fetching data from an API (older style):**

```javascript
fetchUserData(userId, function(user) {
  console.log("Got user:", user.name);
});
```

In every case, the pattern is the same. You're handing off a function and saying: *run this when you have the result.*

## Callback nesting

Now for the part nobody warns you about early enough.

Callbacks work great for one operation. But real applications chain operations. Get the user, then get their orders, then get each product in the order. Each step needs the result from the previous one. So you nest a callback inside a callback inside a callback.

```javascript
getUser(userId, function(user) {
  getOrders(user.id, function(orders) {
    getProduct(orders[0].productId, function(product) {
      getReviews(product.id, function(reviews) {
        console.log(reviews); // finally got what we needed
      });
    });
  });
});
```

Every new requirement pushes the code one level deeper. This is what developers call **callback hell**

![](https://cdn.hashnode.com/uploads/covers/6950d1ca85602739c40abd67/34f5777d-c5c9-4e6f-a6a0-314b32a614cf.png align="center")

The problem isn't just visual. Code this deep is genuinely hard to maintain. Add error handling at each level and it gets worse. Move a step around and you're hunting through nested brackets. Debug it and you're tracing a path through a maze.

This is not a hypothetical problem it's what pushed the JavaScript community to invent **Promises** and then **async/await**. Those tools exist entirely to solve the mess callbacks create when chained.

But here's the important thing to remember: Promises and async/await don't eliminate callbacks. They're built on top of the same concept. Understanding callbacks *is* understanding the foundation of async JavaScript.
