1. A Real-Life Analogy: The Birthday Cake Story
Let’s start with a situation from daily life.
Your best friend has a birthday party tonight. He asks you to bring the cake because your mom works at the best pastry shop in town. At 4 PM, you call your mom and ask her to start baking the cake. It will take one hour to prepare.
Now there are two ways this situation can unfold.
2. Synchronous Way (Blocking)
In the synchronous approach:
- You call your mom.
- You stay on the phone for one full hour.
- You are not allowed to hang up.
- Only after the cake is ready can you go and pick it up.
Key observation
- You cannot do anything else while waiting.
- The waiting time blocks you completely.
This is exactly how synchronous code behaves.
3. Asynchronous Way (Non-Blocking)
In the asynchronous approach:
- You call your mom.
- You ask her to call you back when the cake is ready.
- You hang up immediately.
- You watch Netflix, play games, or go for ice cream 🍦.
- When the cake is ready, your mom calls you back.
Key observation
- You are free to do other work while waiting.
- You only react when the task finishes.
This is how asynchronous code works.
4. Why JavaScript Loves Asynchronous Programming
Many programming languages force you to work synchronously.
JavaScript, however, is designed to be non-blocking by default, which makes it ideal for:
- Web applications
- Servers
- APIs
- File operations
- Network requests
This is one of the biggest reasons JavaScript is so powerful.
5. Synchronous vs Asynchronous: Conceptual Difference
Synchronous Execution
- Code runs line by line
- Each step must finish before the next starts
- Long tasks block the entire program
Asynchronous Execution
- Long tasks are started, not waited for
- Program continues executing the next lines
- Completion is handled later using callbacks, promises, or async/await
6. A JavaScript Example: Printing Numbers
Let’s now see a real JavaScript example that demonstrates this behavior.
Goal
Print the numbers:
1 2 3 4
We create four functions, each responsible for printing one number.
const fs = require("fs");
function printOne() {
const num = 1;
console.log(num);
}
function getNumberTwo() {
return 2;
}
function printTwo() {
const num = getNumberTwo();
console.log(num);
}
function printThree() {
fs.readFile("./numberThree.txt", "utf8", (err, data) => {
if (err) {
console.error(err);
return;
}
console.log(3);
});
}
function printFour() {
const num = 4;
console.log(num);
}
printOne();
printTwo();
printThree();
printFour();
Actual Output
1 2 4 3
7. Understanding What Happened
Let’s break it down step by step.
Execution Order Explained
printOne()→ prints1printTwo()→ prints2printThree()- Starts reading the file
- Does NOT wait
- Returns immediately
printFour()→ prints4- File reading finishes
- Callback executes → prints
3
8. Blocking vs Non-Blocking Calls
Blocking (Synchronous)
- Program waits
- Nothing else executes
- Example:
getNumberTwo()
Non-Blocking (Asynchronous)
- Program continues immediately
- Result handled later
- Example:
fs.readFile()
9. Visualizing Execution Flow
Synchronous Flow
Statement 1 Statement 2 ----> waits until finished Statement 3 Statement 4
Asynchronous Flow
Statement 1 Statement 2 Async Call ----> starts Statement 3 Statement 4 (callback runs later)
10. Common Asynchronous Operations in JavaScript
setTimeout- HTTP requests
- Reading/writing files
- Database queries
- Network communication
11. Why Callbacks Execute Last
JavaScript first finishes all synchronous code.
Only after that does it execute:
- Callbacks
- Timers
- I/O results
This is why printThree finishes after printFour.
