Asher Cohen
Back to posts

JavaScript Async/Await: A Complete Guide

Master modern asynchronous JavaScript with async/await syntax

Introduction

Async/await is the modern way to handle asynchronous operations in JavaScript. Built on top of promises, it provides a cleaner, more readable syntax that looks synchronous while remaining non-blocking.

What is Async/Await?

async and await are keywords that make asynchronous code look and behave like synchronous code.

// Traditional promise-based code
function getUser() {
  return fetch('/api/user')
    .then(response => response.json())
    .then(data => data);
}

// Modern async/await syntax
async function getUser() {
  const response = await fetch('/api/user');
  const data = await response.json();
  return data;
}

The async Keyword

Adding async before a function makes it return a promise automatically.

async function hello() {
  return 'Hello!';
}

hello().then(console.log); // 'Hello!'

The await Keyword

await can only be used inside async functions. It pauses execution until a promise settles.

async function fetchData() {
  const response = await fetch('/api/data');
  const data = await response.json();
  return data;
}

Error Handling

Use try/catch blocks to handle errors:

async function getUser() {
  try {
    const response = await fetch('/api/user');
    const data = await response.json();
    return data;
  } catch (error) {
    console.error('Failed to fetch user:', error);
    throw error;
  }
}

Parallel Execution

Use Promise.all() for parallel execution:

// ❌ Sequential (slow)
async function getData() {
  const user = await fetchUser();
  const posts = await fetchPosts();
  const comments = await fetchComments();
}

// ✅ Parallel (fast)
async function getData() {
  const [user, posts, comments] = await Promise.all([
    fetchUser(),
    fetchPosts(),
    fetchComments()
  ]);
}

Real-World Examples

API Calls

async function createUser(userData) {
  const response = await fetch('/api/users', {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify(userData)
  });
  
  if (!response.ok) throw new Error('Failed');
  return await response.json();
}

Retry Logic

async function fetchWithRetry(url, retries = 3) {
  for (let i = 0; i < retries; i++) {
    try {
      const response = await fetch(url);
      if (response.ok) return response;
    } catch (error) {
      if (i === retries - 1) throw error;
      await new Promise(resolve => setTimeout(resolve, 1000));
    }
  }
}

Common Pitfalls

Forgetting await

// ❌ Missing await
async function getData() {
  const data = fetch('/api/data'); // Returns Promise!
}

// ✅ Correct
async function getData() {
  const data = await fetch('/api/data');
}

Sequential When Parallel Is Possible

// ❌ Slow
const a = await getA();
const b = await getB();

// ✅ Fast
const [a, b] = await Promise.all([getA(), getB()]);

Best Practices

  • Always handle errors with try/catch
  • Use Promise.all for independent operations
  • Keep async functions focused
  • Document async behavior

Conclusion

Async/await makes asynchronous JavaScript more readable and maintainable. Master it to write cleaner, more efficient async code.

#javascript #async #promises