DevPrep
  • Interview Prep
  • Projects
  • Resources
  • Pricing
  • About Us
Submit Question
DevPrep
  • Pricing
  • About Us
Submit Question
  1. Home
  2. Articles
  3. Frontend Engineering
  4. Explain async and await in JavaScript
XLinkedInReddit
MediumFrontend Engineering

Explain async and await in JavaScript

D
DevPrep Team
February 9, 2026·2 min read·0
Table of Contents
  • What Problem Does It Solve?
  • How It Works Under the Hood
  • Common Mistakes
  • Sequential When You Want Parallel
  • Forgetting Error Handling
  • await in Loops
  • Top-Level Await
  • Production Best Practices
  • Summary

By Rahul — Google Frontend Engineer

What Problem Does It Solve?

Before async/await, we had callback hell and promise chains. async/await lets you write asynchronous code that LOOKS synchronous.

// Promise chain
fetchUser(id)
  .then(user => fetchPosts(user.id))
  .then(posts => fetchComments(posts[0].id))
  .then(comments => console.log(comments))
  .catch(err => console.error(err));

// async/await — same thing, readable
async function getComments(id) {
  try {
    const user = await fetchUser(id);
    const posts = await fetchPosts(user.id);
    const comments = await fetchComments(posts[0].id);
    console.log(comments);
  } catch (err) {
    console.error(err);
  }
}

How It Works Under the Hood

An async function ALWAYS returns a Promise. The await keyword pauses execution of the async function until the Promise resolves. Under the hood, it uses microtasks — the code after await is scheduled as a microtask.

async function foo() {
  console.log('A');     // Sync
  await somePromise;    // Pauses here
  console.log('B');     // Runs as microtask after promise resolves
}

// Is equivalent to:
function foo() {
  console.log('A');
  return somePromise.then(() => {
    console.log('B');
  });
}

Common Mistakes

Sequential When You Want Parallel

// BAD — sequential: takes 2 seconds
async function slow() {
  const a = await fetch('/api/a'); // 1 second
  const b = await fetch('/api/b'); // 1 second (waits for a)
}

// GOOD — parallel: takes 1 second
async function fast() {
  const [a, b] = await Promise.all([
    fetch('/api/a'),
    fetch('/api/b')
  ]);
}

Forgetting Error Handling

// BAD — unhandled rejection
async function risky() {
  const data = await fetch('/api/data'); // If this fails?
  return data.json();
}

// GOOD — always handle errors
async function safe() {
  try {
    const data = await fetch('/api/data');
    if (!data.ok) throw new Error(`HTTP ${data.status}`);
    return data.json();
  } catch (err) {
    console.error('Fetch failed:', err);
    return null; // Graceful fallback
  }
}

await in Loops

// BAD — sequential
for (const url of urls) {
  await fetch(url); // One at a time
}

// GOOD — parallel with limit
async function fetchWithLimit(urls, limit = 5) {
  const results = [];
  for (let i = 0; i < urls.length; i += limit) {
    const batch = urls.slice(i, i + limit);
    const batchResults = await Promise.all(batch.map(fetch));
    results.push(...batchResults);
  }
  return results;
}

Top-Level Await

// Works in ES modules (not CommonJS)
const config = await fetch('/config.json').then(r => r.json());
export default config;
// The module waits until config is loaded before exporting

Production Best Practices

  • Always wrap await in try/catch
  • Use Promise.all for independent async operations
  • Add timeouts to avoid hanging forever: Promise.race([fetch(url), timeout(5000)])
  • Use AbortController to cancel fetch requests when components unmount

Summary

async/await is syntactic sugar over Promises. It makes async code readable but introduces subtle bugs around parallelism and error handling. Always use Promise.all for independent operations and try/catch for error handling.

Related Articles

MediumFrontend Engineering

System Design #12: Design a Multi-Step Form Wizard

7 min read
MediumFrontend Engineering

Mastering Senior-Level JavaScript Interview Concepts

2 min read
MediumFrontend Engineering

System Design #9: Design a Collaborative Text Editor

9 min read

Comments (0)

Sign in to leave a comment.

No comments yet. Be the first to comment.

Table of Contents

  • What Problem Does It Solve?
  • How It Works Under the Hood
  • Common Mistakes
  • Sequential When You Want Parallel
  • Forgetting Error Handling
  • await in Loops
  • Top-Level Await
  • Production Best Practices
  • Summary

Series

View all Frontend Engineering articles →

Practice

  • JavaScript
  • DSA
  • Machine Coding
  • System Design

Resources

  • Learning Tracks
  • Articles
  • Roadmaps
  • Compare Concepts
  • Glossary
  • Developer Tools
  • All Questions

Company

  • About
  • Pricing

Legal

  • Privacy Policy
  • Terms of Service
DevPrep

© 2026 DevPrep. All rights reserved.