Module 53 : Synchronous vs Asynchronous
✅ What is Synchronous JavaScript?
Synchronous JavaScript runs line-by-line, meaning each task must complete before the next begins.
Example:
console.log("Start"); console.log("Middle"); console.log("End");
Output:
Start
Middle
End
Each line waits for the previous one to finish. This is the default behavior of JavaScript.
✅ What is Asynchronous JavaScript?
Asynchronous JavaScript allows tasks to run in the background. Instead of blocking the next task, JavaScript hands it off and continues executing the next lines.
Example (with setTimeout):
console.log("Start"); setTimeout(() => { console.log("Inside setTimeout"); }, 2000); console.log("End");
Output:
Start
End
Inside setTimeout
Even though setTimeout is written earlier, it runs after 2 seconds, without blocking the next lines.
JavaScript Execution Model
JavaScript is single-threaded – only one command runs at a time. However, it's non-blocking because of:
The Event Loop
JavaScript uses an event loop to manage the asynchronous code execution.
Stack & Queue:
Call Stack: Where functions are executed.
Callback Queue: Holds async tasks (like setTimeout, fetch).
Event Loop: Transfers tasks from the queue to the stack when the stack is empty.
Analogy
Imagine a chef cooking in a restaurant (synchronous):
He prepares one dish at a time.
If baking takes 30 mins, no other dish is started until baking is complete.
Now imagine (asynchronous):
The chef puts the dish in the oven and starts another one.
A timer goes off when baking is done – the chef returns to finish it.
Coding Methods
1. Synchronous Function Example
function syncTask() { console.log("Task 1"); console.log("Task 2"); } syncTask();
Explanation: Runs top-down, blocking the next line until the current finishes.
2. Asynchronous with setTimeout
function asyncTask() { console.log("Task 1"); setTimeout(() => { console.log("Task 2 - after 2 seconds"); }, 2000); console.log("Task 3"); } asyncTask();
Explanation: is scheduled after 2 seconds. Meanwhile, runs immediately.
3. Using Callbacks
function downloadFile(callback) { console.log("Starting download..."); setTimeout(() => { console.log("Download complete!"); callback(); }, 3000); } downloadFile(() => { console.log("Processing downloaded file..."); });
Explanation: Callback runs after async completes.
4. Using Promises
function fetchData() { return new Promise((resolve, reject) => { setTimeout(() => { resolve("Data fetched"); }, 2000); }); } fetchData().then(data => { console.log(data); });
Explanation: Promises provide a cleaner alternative to callbacks.
5. Using async/await
async function processData() { console.log("Fetching data..."); const result = await fetchData(); // waits for promise to resolve console.log(result); } processData();
Explanation: Makes async code look synchronous and easier to follow.
When too many callbacks are nested, code becomes unreadable.
doA(() => { doB(() => { doC(() => { console.log("Done"); }); }); });
✅ Solution: Use Promises or async/await.
Exercises
Exercise 1: Blocking Code
function blockForSeconds(seconds) { const start = Date.now(); while (Date.now() - start < seconds * 1000) {} } console.log("Start"); blockForSeconds(3); console.log("End");
Modify this to use setTimeout and make it non-blocking.
Exercise 2: Nested Callbacks to Promises
Given:
function step1(callback) { setTimeout(() => { console.log("Step 1 complete"); callback(); }, 1000); } function step2(callback) { setTimeout(() => { console.log("Step 2 complete"); callback(); }, 1000); }
Convert step1 and step2 to return Promises and chain them.
Exercise 3: Async/Await Conversion
Covert this code:
function getUser() { return new Promise(resolve => { setTimeout(() => { resolve({ name: "Rehana", age: 25 }); }, 1500); }); } getUser().then(user => { console.log(user); });
Use async/await to fetch and log the user.
Case Study:
Scenario: Fetching Data from an API
Async function getPosts() { try { const response = await fetch("https://jsonplaceholder.typicode.com/posts"); const posts = await response.json(); console.log(posts); } catch (error) { console.error("Error fetching posts", error); } } getPosts();
✔️ Explanation: Combines async API call with error handling.
Research Insight
JavaScript was originally synchronous due to its browser scripting roots. With the rise of the web (AJAX, APIs, I/O), non-blocking behavior became essential. Hence, modern JavaScript (ES6+) now supports:
Promises (introduced in ES6)
Async/Await (introduced in ES8)
Summary
Feature
Synchronous
Asynchronous
Execution
Line-by-line
Can skip and come back
Blocking
Yes
No
Performance
Slower for I/O
Faster for I/O tasks
Example Tools
Normal functions
setTimeout, fetch, Promises, async/await
Tips
Start with analogies (chef, restaurant, downloading files).
Use animated diagrams to explain the event loop.
Demonstrate using Chrome DevTools and console.log() to show the output.
Highlight errors in callback hell and how promises solve them.
Encourage live coding
Exercise
Build a small app that:
Logs "Starting Task"
Simulates 3 async tasks with different delays using Promises.
Displays “All tasks done” using Promise.all
Rewrites using async/await.
No comments:
Post a Comment