Mastering Callback Functions in JavaScript (with Synchronous vs. Asynchronous Explained)

Mastering Callback Functions in JavaScript (with Synchronous vs. Asynchronous Explained)

With a strong background in WordPress development, focusing on custom themes, plugins, and performance optimization, I’m committed to building efficient, scalable, and engaging websites. I’m actively seeking dynamic WordPress development roles where I can apply my skills to impactful projects and continue enhancing my expertise.        

In JavaScript, functions are first-class citizens, which means they can be passed as arguments, returned from other functions, and assigned to variables. One powerful use of this is through callback functions — especially when dealing with asynchronous operations.

But before diving deeper, let's understand:


👉 What is Synchronous and Asynchronous in JavaScript?

✅ Synchronous

  • In synchronous programming, code is executed line by line, in sequence.
  • Each operation waits for the previous one to complete.
  • If one task takes a long time, it blocks everything that comes after it.

👉 Example:

console.log("Task 1");
console.log("Task 2");
console.log("Task 3");        

All lines will run one after another, in order.


✅ Asynchronous

  • Asynchronous programming allows tasks to run in the background.
  • It does not block the execution of the remaining code.
  • Functions like 𝘀𝗲𝘁𝗧𝗶𝗺𝗲𝗼𝘂𝘁(), 𝗳𝗲𝘁𝗰𝗵(), and 𝗲𝘃𝗲𝗻𝘁 𝗹𝗶𝘀𝘁𝗲𝗻𝗲𝗿𝘀 are asynchronous.

👉 Example:

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

Here, 𝗧𝗮𝘀𝗸 𝟯 will execute before 𝗧𝗮𝘀𝗸 𝟮, showing that 𝘀𝗲𝘁𝗧𝗶𝗺𝗲𝗼𝘂𝘁 runs asynchronously.


✅ What is a Callback Function?

A callback function is a function that is passed as an argument to another function and is executed after the completion of that function, often used for asynchronous operations.


✅ Callback Example (Synchronous):

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

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

greetUser("Sujoy", sayGoodbye);        

The 𝘀𝗮𝘆𝗚𝗼𝗼𝗱𝗯𝘆𝗲 function is passed as a callback and runs after the greeting.

Output:

Hello, Sujoy!

Goodbye!


✅ Callback Example (Asynchronous):

console.log("Start");

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

console.log("End");        

This shows that JavaScript can start other tasks and run the callback when the timer is over.

➡️ This function is not running immediately; it is given to setTimeout to call back later (after 2 seconds).

👉 So, that little function() { ... } is our callback function! It’s just an anonymous (nameless) callback function passed directly inside setTimeout().


✅ Why do we need callbacks?

  • Handle asynchronous operations like API calls or delayed actions
  • Ensure certain code executes only after tasks are completed
  • Maintain control over the flow of execution


✅ Common Callback Use Cases:

  • Event listeners
  • 𝘀𝗲𝘁𝗧𝗶𝗺𝗲𝗼𝘂𝘁() and 𝘀𝗲𝘁𝗜𝗻𝘁𝗲𝗿𝘃𝗮𝗹()
  • AJAX requests (before promises and async/await)
  • Array methods like 𝗺𝗮𝗽, 𝗳𝗶𝗹𝘁𝗲𝗿, 𝗳𝗼𝗿𝗘𝗮𝗰𝗵


🔥 What is Callback Hell?

When callbacks are nested inside multiple callbacks, it becomes messy and hard to manage — known as callback hell.

Example:

function getData(callback) {
    setTimeout(() => {
        console.log("getData done");
        callback("dataA");
    }, 1000);
}

function processData(a, callback) {
    setTimeout(() => {
        console.log("processData done");
        callback("dataB");
    }, 1000);
}

function saveData(b, callback) {
    setTimeout(() => {
        console.log("saveData done");
        callback("done");
    }, 1000);
}

getData(function(a){
    processData(a, function(b){
        saveData(b, function(c){
            console.log('Data saved!');
        });
    });
});        

Output:

getData done

processData done

saveData done

Data saved!

✅ How it works step by step:

𝗴𝗲𝘁𝗗𝗮𝘁𝗮 𝗶𝘀 𝗰𝗮𝗹𝗹𝗲𝗱.

  • It waits 1 second (using setTimeout),
  • then prints getData done,
  • and calls its callback function with "dataA".

𝗜𝗻𝘀𝗶𝗱𝗲 𝘁𝗵𝗲 𝗰𝗮𝗹𝗹𝗯𝗮𝗰𝗸 𝗼𝗳 𝗴𝗲𝘁𝗗𝗮𝘁𝗮, 𝘄𝗲 𝗰𝗮𝗹𝗹 𝗽𝗿𝗼𝗰𝗲𝘀𝘀𝗗𝗮𝘁𝗮(𝗮, 𝗰𝗮𝗹𝗹𝗯𝗮𝗰𝗸).

  • It waits 1 second,
  • prints processData done,
  • and then calls its callback with "dataB".

𝗜𝗻𝘀𝗶𝗱𝗲 𝘁𝗵𝗮𝘁 𝗰𝗮𝗹𝗹𝗯𝗮𝗰𝗸, 𝘄𝗲 𝗰𝗮𝗹𝗹 𝘀𝗮𝘃𝗲𝗗𝗮𝘁𝗮(𝗯, 𝗰𝗮𝗹𝗹𝗯𝗮𝗰𝗸).

  • It waits 1 second,
  • prints saveData done,
  • and calls its callback with "done".

𝗙𝗶𝗻𝗮𝗹𝗹𝘆, 𝗶𝗻𝘀𝗶𝗱𝗲 𝘁𝗵𝗮𝘁 𝗹𝗮𝘀𝘁 𝗰𝗮𝗹𝗹𝗯𝗮𝗰𝗸, 𝘆𝗼𝘂 𝗽𝗿𝗶𝗻𝘁:

  • Data saved!

👉 Solution: Use Promises or async/await for cleaner code.


✅ Conclusion:

  • Synchronous code runs line by line and can block execution.
  • Asynchronous code allows operations to happen in the background without blocking.
  • Callbacks are key to handling asynchronous operations but can lead to callback hell if not managed well.
  • Start with callbacks, move on to Promises, and eventually use async/await for modern and clean JavaScript coding.

If you're looking for a WordPress developer with expertise in database management and site optimization, feel free to connect with me here on LinkedIn or send me a message to discuss how we can collaborate.        


To view or add a comment, sign in

More articles by Sujoy Sen

Insights from the community

Others also viewed

Explore topics