Asynchronous JavaScript

Callbacks, Promises, and async/await patterns

Async Patterns

JavaScript is single-threaded. Asynchronous code lets it handle I/O without blocking. The evolution: callbacks → Promises → async/await.

js
// Async Evolution
// 1. Callbacks — leads to "callback hell"
fs.readFile("a.txt", (err, dataA) => {
  fs.readFile("b.txt", (err, dataB) => {
    fs.readFile("c.txt", (err, dataC) => {
      // deeply nested = hard to read
    });
  });
});

// 2. Promises — chainable, .then/.catch
function fetchUser(id) {
  return fetch(`/api/users/${id}`)
    .then(res => {
      if (!res.ok) throw new Error("Not found");
      return res.json();
    });
}
fetchUser(1).then(user => console.log(user)).catch(console.error);

// 3. async/await — cleanest syntax
async function getUser(id) {
  try {
    const res = await fetch(`/api/users/${id}`);
    if (!res.ok) throw new Error("Not found");
    return await res.json();
  } catch (err) {
    console.error("Failed:", err.message);
  }
}

// Parallel execution
const [users, posts] = await Promise.all([
  fetch("/api/users").then(r => r.json()),
  fetch("/api/posts").then(r => r.json()),
]);

// Promise.allSettled — don't fail if one rejects
const results = await Promise.allSettled([p1, p2, p3]);
// results: [{ status: "fulfilled", value }, { status: "rejected", reason }]

💬 Difference between Promise.all and Promise.allSettled?

Promise.all rejects immediately if ANY promise rejects (fail-fast). Promise.allSettled waits for ALL to complete and returns results for each (fulfilled or rejected). Use allSettled when you need all results regardless of failures.