Skip to main content

Command Palette

Search for a command to run...

Callbacks in JavaScript: Why They Exist

Updated
4 min read
Callbacks in JavaScript: Why They Exist

Hello guys, in this article we are going to learn about the callback functions in the js, what are they , why we use them and the problems we face while using them.

Callback function

A callback function is a function passed into another function as an argument, which is then invoked inside the outer function to complete some kind of action.

There are two ways in which the callback may be called: synchronous and asynchronous. Synchronous callbacks are called immediately after the invocation of the outer function, while asynchronous callbacks are called at some point later, after an asynchronous operation has completed.

let value = 1;

function doSomething(callback) {

// synchromous execution
 callback();

// asynchronous execution
setTimeout(callback,0);
}

doSomething(() => {
  value = 2;
});
console.log(value); // 1 or 2?

Here , in this example the callback is executed synchronously and the output will be 2.

Note - Examples of synchronous callbacks include the callbacks passed to Array.prototype.map(), Array.prototype.forEach(), etc. Examples of asynchronous callbacks include the callbacks passed to setTimeout() and Promise.prototype.then().

Why callbacks are used in asynchronous programming

JavaScript executes code line by line (synchronously), but sometimes we need to wait for a task to complete . Many operations don't finish instantly like api call , timers, file reading and DB queries. Callbacks let you continue execution without blocking, and define what should happen later.

Callback for async operation

console.log("Start");

setTimeout(function () {
    console.log("Inside setTimeout");
}, 2000);

console.log("End");
  • setTimeout() is an asynchronous function that takes a callback to execute after 2 seconds.

  • The rest of the code continues executing without waiting.

Callback usage in common scenarios

  1. Handling Asynchronous Operations
    Callbacks are widely used in

    • API requests (fetching data)

    • Reading files (Node.js file system)

    • Event listeners (clicks, keyboard inputs)

    • Database queries (retrieving data)

  2. Callbacks in Functions Handling Operations
    When a function needs to execute different behaviors based on input, callbacks make the function flexible.

    function calc(a, b, callback) {
        return callback(a, b);
    }
    
    function add(x, y) {
        return x + y;
    }
    
    function mul(x, y) {
        return x * y;
    }
    
    console.log(calc(5, 3, add));    
    console.log(calc(5, 3, mul));
    
    // calculate() receives two numbers and a function (add or multiply).
    
    // The passed function is executed inside calculate().
    
  3. Callbacks in Event Listeners
    JavaScript is event-driven, and callbacks handle user interactions like clicks and key presses.

    document
    .getElementById("myButton")
    .addEventListener("click", function () {
        console.log("Button clicked!");
    });
    
  4. Callbacks in API Calls (Fetching Data)
    Callbacks are useful when retrieving data from APIs.

    function fetch(callback) {
        fetch("https://jsonplaceholder.typicode.com/todos/1")
            .then(response => response.json())
            .then(data => callback(data))
            .catch(error => console.error("Error:", error));
    }
    
    function handle(data) {
        console.log("Fetched Data:", data);
    }
    
    fetch(handle);
    

Problems with Callbacks

Callbacks are powerful, but they come with some real pain points—especially as your app grows.

  1. Callback Hell (Nested Callbacks)

    function step1(callback) {
        setTimeout(() => {
            console.log("Step 1 completed");
            callback();
        }, 1000);
    }
    
    function step2(callback) {
        setTimeout(() => {
            console.log("Step 2 completed");
            callback();
        }, 1000);
    }
    
    function step3(callback) {
        setTimeout(() => {
            console.log("Step 3 completed");
            callback();
        }, 1000);
    }
    
    step1(() => {
        step2(() => {
            step3(() => {
                console.log("All steps completed");
            });
        });
    });
    

    As the number of steps increases, the nesting grows deeper, making the code difficult to manage.

  2. Error Handling Issues in Callbacks

    function divide(a, b, callback) {
        if (b === 0) {
            callback(new Error("Cannot divide by zero"), null);
        } else {
            callback(null, a / b);
        }
    }
    
    function result(error, result) {
        if (error) {
            console.log("Error:", error.message);
        } else {
            console.log("Result:", result);
        }
    }
    
    divide(10, 2, result);
    divide(10, 0, result);
    

The main pain-point to work with callback is the code readability . It is majorly affected by the callbacks and can become much difficult to use the callbacks.
We can use the promises or async/await as the callbacks alternative.