Asynchronous JavaScript: Event Loop, Promises, Combinators & async/await

๐ŸŸจ JavaScript (ES2026+) ๐ŸŸข Lesson 18 ๐Ÿ“‚ Phase 15: Asynchronous JavaScript ๐Ÿ“… 2026 Edition
๐Ÿ“Œ Covered in this lesson: Sync vs Async ยท Event Loop & Microtasks ยท Callbacks & Hell ยท Promise States & Chaining ยท all/allSettled/race/any ยท async/await ยท Sequential vs Parallel ยท 4 Pipelines

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.

1Sync vs Async & The Event Loop Architecture โญ

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:

1. Call Stack (LIFO: Synchronous JS Execution)
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)
2Callbacks vs Callback Hell (The Pyramid of Doom)

Multiple dependent asynchronous operations ni nested callbacks tho raste code deeply indented Pyramid of Doom ga maruthundhi (hard to debug, maintain, and handle errors):

JavaScript โ€” Callback Hell (โŒ Legacy Anti-Pattern)
// โŒ 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);
            });
        });
    });
});
3Promises & The 3 Lifecycle States

A Promise is an Object representing the eventual completion (fulfillment) or failure (rejection) of an asynchronous task:

Promise StateMeaningTriggered By
1. PendingInitial state, async operation is still executing in background.Promise construction
2. FulfilledOperation completed successfully with a result value.resolve(value) $ ightarrow$ triggers .then()
3. RejectedOperation failed with an error reason.reject(error) $ ightarrow$ triggers .catch()
JavaScript โ€” Promise Construction & Chaining โ–ถ Run Code
"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.");
    });
4The 4 Modern Promise Combinators (Crucial Interview Topic)
CombinatorWhen 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.
5async / await & Sequential vs Parallel Optimization

async/await allows asynchronous code to be written cleanly in a synchronous-looking sequential style with standard try...catch error handling:

JavaScript โ€” User Curriculum Example โ–ถ Run Code
"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();
1. Sequential Requests (Slow ๐ŸŒ)
// Takes 2s + 2s = 4 Seconds total!
const user = await fetchUser();
const posts = await fetchPosts();
2. Parallel Requests (Fast โšก)
// Runs in parallel: Takes only 2 Seconds!
const [user, posts] = await Promise.all([
    fetchUser(),
    fetchPosts()
]);
64 Real-World Production Async Pipelines

Mastering asynchronous JavaScript through 4 production architectures:

Pipeline 1: Parallel Dashboard Data Aggregator

JavaScript โ€” Parallel Promise.all โ–ถ Run Code
"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()

JavaScript โ€” Timeout with Promise.race โ–ถ Run Code
"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()

JavaScript โ€” Promise.any CDN โ–ถ Run Code
"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

JavaScript โ€” Sequential Steps โ–ถ Run Code
"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);
OC
Written and reviewed by Our Compiler Technical Team ยท Updated for JavaScript ES2026+