JavaScript Callback Functions

A callback function is a function you pass as an argument to another function. The other function calls it at the right time. You hand over a task, and the function calls you back when the work is done — just like leaving your number at a restaurant so they call you when your table is ready.

Why Do We Need Callback Functions?

JavaScript runs one task at a time. When a task takes time — like loading data from a server — you do not want the whole program to freeze and wait. A callback lets you say: "When you finish that, run this code." This keeps the program running smoothly.

A Simple Callback Example

Think of a greeting machine. You tell it your name and give it a function to call when it is ready to greet you.

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

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

greet("Riya", sayBye);
// Output:
// Hello, Riya
// Goodbye!

sayBye is the callback. greet receives it and calls it after doing its own work.

Diagram: How a Callback Works

┌─────────────────────────────────────────┐
│           Your Code                     │
│                                         │
│  greet("Riya", sayBye)                  │
│       │                                 │
│       ▼                                 │
│  greet runs → prints "Hello, Riya"      │
│       │                                 │
│       ▼                                 │
│  calls callback → sayBye runs           │
│       │                                 │
│       ▼                                 │
│  prints "Goodbye!"                      │
└─────────────────────────────────────────┘

Passing a Callback Inline

You can write the callback directly without naming it first. This is called an anonymous function.

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

greet("Aman", function() {
  console.log("See you later!");
});

The function inside greet() has no name. It lives only for that one call.

Callbacks with Data

A callback can also receive data from the outer function. This is common when you get results back from a task.

function addNumbers(a, b, callback) {
  let result = a + b;
  callback(result);
}

addNumbers(5, 3, function(sum) {
  console.log("The sum is: " + sum);
});
// Output: The sum is: 8

Diagram: Callback Receiving Data

addNumbers(5, 3, callback)
     │
     ▼
  result = 5 + 3 = 8
     │
     ▼
  callback(8)  ──► prints "The sum is: 8"

Real-World Use: setTimeout

setTimeout is a built-in JavaScript function that uses a callback. You give it a function and a delay in milliseconds. It calls your function after the delay.

console.log("Order placed");

setTimeout(function() {
  console.log("Order delivered!");
}, 2000);

console.log("Waiting...");

// Output:
// Order placed
// Waiting...
// Order delivered!  (after 2 seconds)

Notice that "Waiting..." prints before "Order delivered!" even though it comes after the setTimeout line. JavaScript does not wait for the timer — it keeps going and comes back when the timer finishes.

Diagram: setTimeout Flow

Line 1: "Order placed"   → prints immediately
Line 2: setTimeout(...)  → starts a 2-second timer, moves on
Line 3: "Waiting..."     → prints immediately
  ....  (2 seconds pass)
Timer done → callback runs → "Order delivered!"

Array Methods That Use Callbacks

Many built-in array methods accept callbacks. These are some of the most common ones:

forEach

let fruits = ["Apple", "Banana", "Mango"];

fruits.forEach(function(fruit) {
  console.log(fruit);
});
// Prints each fruit one by one

filter

let numbers = [1, 2, 3, 4, 5, 6];

let evenNumbers = numbers.filter(function(num) {
  return num % 2 === 0;
});

console.log(evenNumbers); // [2, 4, 6]

map

let prices = [100, 200, 300];

let discounted = prices.map(function(price) {
  return price * 0.9;
});

console.log(discounted); // [90, 180, 270]

The Problem: Callback Hell

When you nest many callbacks inside each other, the code becomes hard to read. This is called callback hell or the pyramid of doom.

getUser(function(user) {
  getOrders(user.id, function(orders) {
    getDetails(orders[0], function(details) {
      console.log(details);
    });
  });
});

Diagram: Callback Hell (Pyramid Shape)

getUser(
  getOrders(
    getDetails(
      console.log()
    )
  )
)
Each level adds one more indent — hard to read and debug.

Promises and async/await were introduced to solve callback hell. They let you write the same logic in a flat, easier-to-read way.

Synchronous vs Asynchronous Callbacks

Not all callbacks are asynchronous. A callback given to forEach runs immediately — that is a synchronous callback. A callback given to setTimeout runs later — that is an asynchronous callback.

TypeWhen It RunsExample
SynchronousImmediately, in orderforEach, map, filter
AsynchronousLater, after a task finishessetTimeout, fetch, file read

Best Practices

  • Keep callbacks short and focused on one job.
  • Name your callback functions to make errors easier to trace.
  • Avoid nesting more than two levels of callbacks — use Promises instead.
  • Always handle errors inside asynchronous callbacks.

Summary

A callback function is a function passed into another function and called when needed. It is the foundation of asynchronous programming in JavaScript. Array methods like forEach, map, and filter all use callbacks. When callbacks nest too deep, they create callback hell — a problem that Promises and async/await solve cleanly.

Leave a Comment

Your email address will not be published. Required fields are marked *