Parallel Async Operations

Hard

By default, async/await runs operations sequentially. To run operations in parallel, use Promise.all() with await. This is one of the most common performance optimizations in JavaScript. Understanding when to parallelize and when to sequence is essential for writing efficient async code.

Interactive Visualization

Sequential Execution
0s2.0s4.0s
fetchUser()
pending
fetchPosts()
idle
Elapsed:0.0s
Awaiting:fetchUser()
Sequential
1async function sequential() {
2 const user = await fetchUser(); // 2s
3 const posts = await fetchPosts(); // 2s
4 return { user, posts };
5}
6// Total: 4 seconds (2 + 2)
Parallel
1async function parallel() {
2 const [user, posts] = await Promise.all([
3 fetchUser(), // 2s
4 fetchPosts(), // 2s (runs at same time!)
5 ]);
6 return { user, posts };
7}
8// Total: 2 seconds (max of 2, 2)
Sequential: We start fetchUser() and WAIT for it to complete before starting anything else.
1 / 5
Key Insight: Sequential: 4s (2+2). Parallel: 2s (max). When operations are independent, use Promise.all!

Key Points

  • await runs sequentially by default
  • Use Promise.all() to run operations in parallel
  • Start operations before awaiting to run in parallel
  • Do NOT use await in a loop for independent operations
  • Promise.all() fails fast on first rejection
  • Use Promise.allSettled() when partial success is acceptable

Code Examples

Sequential vs Parallel

// ❌ SEQUENTIAL (slow)
async function sequential() {
  const user = await fetchUser();      // 100ms
  const posts = await fetchPosts();    // 100ms
  const comments = await fetchComments(); // 100ms
  // Total: 300ms
  return { user, posts, comments };
}

// ✅ PARALLEL (fast)
async function parallel() {
  const [user, posts, comments] = await Promise.all([
    fetchUser(),      // Start immediately
    fetchPosts(),     // Start immediately
    fetchComments()   // Start immediately
  ]);
  // Total: ~100ms (max of all)
  return { user, posts, comments };
}

Promise.all() runs all Promises simultaneously, waiting for all to complete.

The Loop Anti-Pattern

// ❌ WRONG: Sequential in loop
async function fetchUsers(ids) {
  const users = [];
  for (const id of ids) {
    const user = await fetchUser(id); // Waits each iteration!
    users.push(user);
  }
  return users; // Slow: ids.length × fetch time
}

// ✅ CORRECT: Parallel with map
async function fetchUsers(ids) {
  const promises = ids.map(id => fetchUser(id));
  const users = await Promise.all(promises);
  return users; // Fast: ~single fetch time
}

// Alternative with Promise.all()
async function fetchUsers(ids) {
  return Promise.all(ids.map(id => fetchUser(id)));
}

Never use await inside a loop for independent operations. Use map + Promise.all().

Start Before Await

// ✅ Good: Start operations, then await
async function fetchDashboard() {
  // Start all operations immediately
  const userPromise = fetchUser();
  const postsPromise = fetchPosts();
  const statsPromise = fetchStats();
  
  // Now await results (already running in parallel!)
  const user = await userPromise;
  const posts = await postsPromise;
  const stats = await statsPromise;
  
  return { user, posts, stats };
}

// Same as Promise.all() but more flexible

Start Promises before awaiting to run them in parallel. Then await results.

Partial Success with allSettled

// When some can fail but you want the rest
async function fetchWithFallbacks(urls) {
  const results = await Promise.allSettled(
    urls.map(url => fetch(url))
  );
  
  const successes = results
    .filter(r => r.status === 'fulfilled')
    .map(r => r.value);
  
  const failures = results
    .filter(r => r.status === 'rejected')
    .map(r => r.reason);
  
  console.log('Loaded:', successes.length);
  console.log('Failed:', failures.length);
  
  return successes; // Return what worked
}

Use Promise.allSettled() when you need all results regardless of individual failures.

Common Mistakes

  • Using await inside loops for independent operations
  • Not realizing sequential is the default
  • Using Promise.all() when operations depend on each other
  • Not handling partial failures appropriately

Interview Tips

  • Know how to parallelize with Promise.all()
  • Know the "await in loop" anti-pattern
  • Understand when to use all() vs allSettled()
  • Be able to optimize slow sequential code