Asynchronous JavaScript: Event Loop, Promises, Combinators & async/await
Welcome to Phase 15: Asynchronous JavaScript & Promises! JavaScript is a single-threaded language with a non-blocking asynchronous event-driven runtime. In this comprehensive masterclass guide, you will master the inner workings of the Event Loop (Call Stack, Web APIs, Callback Task Queue, and Microtask Queue priority), overcome Callback Hell, explore Promises and their 3 lifecycle states, master the 4 modern Promise combinators (Promise.all, Promise.allSettled, Promise.race, Promise.any), master async/await syntax, and optimize network performance through Parallel vs Sequential execution.
Synchronous code line-by-line execute avthundhi (blocking the main UI thread). Asynchronous code background threads (Web APIs) lo run ayi, complete ayyaka Call Stack loki push avthundhi:
2. Web APIs / C++ Threads (Timers, fetch(), DOM Events running in background)
3. Microtask Queue (Promises, await, queueMicrotask) โก HIGHEST PRIORITY!
4. Task / Callback Queue (setTimeout, setInterval, I/O)
5. Event Loop (Monitors Stack; when Stack is EMPTY, drains Microtasks first, then 1 Macrotask)
Multiple dependent asynchronous operations ni nested callbacks tho raste code deeply indented Pyramid of Doom ga maruthundhi (hard to debug, maintain, and handle errors):
// โ Callback Hell: Inversion of control & impossible error handling
getUser(1, (user) => {
getOrders(user.id, (orders) => {
getOrderDetails(orders[0].id, (details) => {
getInvoice(details.invoiceId, (invoice) => {
console.log("Final Invoice:", invoice);
});
});
});
});
A Promise is an Object representing the eventual completion (fulfillment) or failure (rejection) of an asynchronous task:
| Promise State | Meaning | Triggered By |
|---|---|---|
1. Pending | Initial state, async operation is still executing in background. | Promise construction |
2. Fulfilled | Operation completed successfully with a result value. | resolve(value) $
ightarrow$ triggers .then() |
3. Rejected | Operation failed with an error reason. | reject(error) $
ightarrow$ triggers .catch() |
"use strict";
function fetchProductPrice(productId) {
return new Promise((resolve, reject) => {
setTimeout(() => {
if (productId > 0) {
resolve({ id: productId, price: 999 });
} else {
reject(new Error("Invalid Product ID!"));
}
}, 500);
});
}
// Consuming Promise with .then(), .catch() and .finally()
fetchProductPrice(101)
.then(product => {
console.log("Product Fetched:", product);
return product.price * 1.18; // Chain transform
})
.then(totalWithTax => {
console.log("Total with 18% Tax: Rs." + totalWithTax.toFixed(2));
})
.catch(err => {
console.error("Error:", err.message);
})
.finally(() => {
console.log("Transaction pipeline completed.");
});
| Combinator | When does it Resolve? | When does it Reject? | Key Use Case |
|---|---|---|---|
Promise.all([p1, p2]) |
When ALL promises resolve successfully. | Fails Fast: Rejects immediately if ANY single promise rejects! | All dependent data needed simultaneously (e.g. User Profile + Settings). |
Promise.allSettled([p1, p2]) โญ ES2020 |
Waits for ALL promises to finish (either resolved or rejected). | Never Rejects! Returns array of status objects. | Bulk analytics or operations where partial failures are acceptable. |
Promise.race([p1, p2]) |
Settles as soon as the FIRST promise settles (resolves OR rejects). | Rejects if the fastest promise rejects. | Network request timeout wrappers. |
Promise.any([p1, p2]) โญ ES2021 |
Resolves as soon as the FIRST SUCCESSFUL promise fulfills. | Rejects only if ALL promises fail (AggregateError). |
Fastest CDN / Mirror download fallbacks. |
async/await allows asynchronous code to be written cleanly in a synchronous-looking sequential style with standard try...catch error handling:
"use strict";
function getData() {
return new Promise(resolve => {
setTimeout(() => resolve("Data received successfully!"), 1000);
});
}
async function showData() {
console.log("Fetching data in background...");
const result = await getData(); // Pauses async execution until resolved!
console.log("Result:", result);
}
showData();
// Takes 2s + 2s = 4 Seconds total!
const user = await fetchUser();
const posts = await fetchPosts();
// Runs in parallel: Takes only 2 Seconds!
const [user, posts] = await Promise.all([
fetchUser(),
fetchPosts()
]);
Mastering asynchronous JavaScript through 4 production architectures:
Pipeline 1: Parallel Dashboard Data Aggregator
"use strict";
async function fetchAnalyticsDashboard() {
const fetchUsers = () => new Promise(res => setTimeout(() => res({ totalUsers: 1450 }), 200));
const fetchRevenue = () => new Promise(res => setTimeout(() => res({ mrr: "$42,000" }), 300));
const fetchTraffic = () => new Promise(res => setTimeout(() => res({ dailyVisits: 89000 }), 150));
console.time("DashboardLoad");
const [users, revenue, traffic] = await Promise.all([
fetchUsers(),
fetchRevenue(),
fetchTraffic()
]);
console.timeEnd("DashboardLoad"); // ~300ms total!
console.log("Dashboard Loaded:", { ...users, ...revenue, ...traffic });
}
fetchAnalyticsDashboard();
Pipeline 2: API Request Timeout Wrapper via Promise.race()
"use strict";
function withTimeout(promise, msTimeout = 2000) {
const timeout = new Promise((_, reject) => {
setTimeout(() => reject(new Error("Request Timed Out after " + msTimeout + "ms!")), msTimeout);
});
return Promise.race([promise, timeout]);
}
const slowApi = new Promise(res => setTimeout(() => res("Slow Data"), 3000));
withTimeout(slowApi, 1000)
.then(data => console.log(data))
.catch(err => console.error("Caught Timeout:", err.message)); // Triggers Timeout!
Pipeline 3: CDN Mirror Fallback with Promise.any()
"use strict";
async function fetchFastestCDN() {
const cdn1 = new Promise((_, rej) => setTimeout(() => rej("CDN1 Offline"), 100));
const cdn2 = new Promise(res => setTimeout(() => res("CDN2 (Singapore)"), 300));
const cdn3 = new Promise(res => setTimeout(() => res("CDN3 (Mumbai)"), 200));
try {
const fastest = await Promise.any([cdn1, cdn2, cdn3]);
console.log("โ
Connected to Fastest Available Server:", fastest); // CDN3 (Mumbai)
} catch (err) {
console.error("All CDNs failed:", err);
}
}
fetchFastestCDN();
Pipeline 4: Step-by-Step E-Commerce Checkout Pipeline
"use strict";
async function processOrder(orderId) {
try {
console.log("Step 1: Validating Inventory for Order #" + orderId + "...");
await new Promise(r => setTimeout(r, 200));
console.log("Step 2: Charging Payment Gateway...");
await new Promise(r => setTimeout(r, 300));
console.log("Step 3: Generating Invoice & Dispatching Shipment...");
await new Promise(r => setTimeout(r, 200));
console.log("๐ Order #" + orderId + " Successfully Placed & Dispatched!");
} catch (err) {
console.error("Order processing failed:", err.message);
}
}
processOrder(98452);