Skip to main content

Command Palette

Search for a command to run...

Callbacks in JavaScript

Why They Exist

Updated
•3 min read•View as Markdown

What is a Callback Function?

A callback function is simply a function that is passed as an argument to another function

Example:

function operation(a,b,cb){
    console.log(cb(a,b))
}

const sum = (a,b) => a+b
const difference = (a,b) => a-b
const multiplication = (a,b) => a*b
const division = (a,b) => a/b

operation(10,5, sum) // 15
operation(10,5, difference) // 5
operation(10,5, multiplication) // 50
operation(10,5, division) // 2

Why Callbacks Exist?

JavaScript is single-threaded, meaning it can execute only one task at a time.

But real-world applications need to:

  • Fetch data from APIs

  • Read files

  • Handle user interactions

  • Wait for timers

If JavaScript waited for each task to complete synchronously, the application would freeze.

const data = fetchDataFromServer(); // takes 5 seconds
console.log(data);

This would block everything for 5 seconds. Thus our application will less responsive. To fix this we use callbacks.

Solution: Asynchronous Execution with Callbacks

function fetchData(callback) {
  setTimeout(() => {
    callback("Data received");
  }, 2000);
}

fetchData((data) => {
  console.log(data);
});

👉 Instead of blocking:

  • The task runs in the background

  • Callback executes after completion

Callbacks in Asynchronous Programming

Example: setTimeout

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

Example: API Simulation

function getUser(callback) {
  setTimeout(() => {
    callback({ username: "krish", email: "krish@example.com" });
  }, 1000);
}

getUser((user) => {
  console.log(user);
});

The callback ensures code runs only when data is ready.

Common Use Cases of Callbacks

1. Event Handling

document.getElementById("btn").addEventListener("click", () =>{ 
    console.log("Button clicked!"); 
});

2. File System (Node.js)

import fs from "fs"; 

fs.readFile("file.txt", "utf-8", (err, data) => { 

    if (err) throw err;   
    console.log(data); 
});

3. API Calls (Before Promises)

function fetchData(callback) { 
    setTimeout(() => { 
        callback("API response"); 
    }, 1000); 
}

4. Array Methods

const numbers = [1, 2, 3]; 
numbers.forEach((num) => { 
    console.log(num); 
});

Basic problem of callback nesting

Callbacks work well… until they start nesting deeply.

Example:

getUser((user) => {
  getOrders(user.id, (orders) => {
    getOrderDetails(orders[0], (details) => {
      console.log(details);
    });
  });
});

Problems:

  • Hard to read

  • Difficult to debug

  • Error handling becomes messy

  • Code becomes pyramid-shaped

Solutions:

  • Start using promises

  • Try using async await

These are built on top of callbacks, not replacements at the core level.