~/hackweb.dev
JavaScript Async/Await Patterns
Quiz
...

JavaScript Async/Await Patterns

beginner · updated Tue Sep 08 2026Contribute

Master async/await syntax for cleaner asynchronous code.

JavaScript Async/Await Patterns

Write asynchronous code that looks synchronous.

Basic Async/Await

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

fetchData().then(data => console.log(data));

Error Handling

async function getData() {
  try {
    let response = await fetch("/api/data");
    if (!response.ok) throw new Error(`HTTP ${response.status}`);
    return await response.json();
  } catch (error) {
    console.error("Error:", error.message);
    return null;
  }
}

Sequential vs Parallel

Sequential — when each step depends on the previous result:

async function sequential() {
  let user = await fetchUser();
  let posts = await fetchPosts(user.id);
  return { user, posts };
}

Parallel — when operations are independent:

async function parallel() {
  let [user, posts] = await Promise.all([fetchUser(), fetchPosts()]);
  return { user, posts };
}

Remember: Parallel is faster when operations don’t depend on each other.

API Service Example

class ApiService {
  #baseUrl;
  #cache = new Map();
  constructor(baseUrl) { this.#baseUrl = baseUrl; }

  async get(endpoint) {
    let url = `${this.#baseUrl}${endpoint}`;
    if (this.#cache.has(url)) return this.#cache.get(url);
    let response = await fetch(url);
    if (!response.ok) throw new Error(`HTTP ${response.status}`);
    let data = await response.json();
    this.#cache.set(url, data);
    return data;
  }

  async post(endpoint, body) {
    let response = await fetch(`${this.#baseUrl}${endpoint}`, {
      method: "POST",
      headers: { "Content-Type": "application/json" },
      body: JSON.stringify(body)
    });
    if (!response.ok) throw new Error(`HTTP ${response.status}`);
    return await response.json();
  }
}

Batch Processing

async function batchProcess(items, batchSize = 10) {
  let results = [];
  for (let i = 0; i < items.length; i += batchSize) {
    let batch = items.slice(i, i + batchSize);
    let batchResults = await Promise.all(batch.map(item => processItem(item)));
    results.push(...batchResults);
  }
  return results;
}

Retry and Timeout

function withRetry(fn, maxAttempts = 3, delay = 1000) {
  return async function(...args) {
    for (let i = 1; i <= maxAttempts; i++) {
      try { return await fn(...args); }
      catch (error) {
        if (i === maxAttempts) throw error;
        await new Promise(r => setTimeout(r, delay));
      }
    }
  };
}

function withTimeout(promise, ms = 5000) {
  return Promise.race([
    promise,
    new Promise((_, reject) => setTimeout(() => reject(new Error("Timeout")), ms))
  ]);
}

Best Practices

  • Use async/await — Cleaner than .then()
  • Handle errors with try/catch — Always catch errors
  • Use Promise.all() for parallel — Don’t await sequentially
  • Avoid unnecessary awaits — Don’t await synchronous values

Common Mistakes

  • Forgetting to await — Returns promise instead of value
  • Missing error handling — Unhandled rejections
  • Overusing await — Sequential when parallel is possible
  • Awaiting in loops — Use Promise.all() instead