Async/Await: Common Mistakes

Async/await makes promises easier, but there are still pitfalls. Here are the mistakes I see most often.

Mistake 1: Forgetting await

// ❌ Returns a promise, not the data
async function getUser(id) {
  const user = fetchUser(id); // forgot await
  return user.name; // user is a Promise!
}

// ✅ Correct
async function getUser(id) {
  const user = await fetchUser(id);
  return user.name;
}

Mistake 2: Sequential When Parallel is Fine

// ❌ Slow - runs one after another
async function getData() {
  const users = await fetchUsers();
  const products = await fetchProducts();
  const orders = await fetchOrders();
  // Total time: sum of all three
}

// ✅ Fast - runs in parallel
async function getData() {
  const [users, products, orders] = await Promise.all([
    fetchUsers(),
    fetchProducts(),
    fetchOrders()
  ]);
  // Total time: max of the three
}

If operations don't depend on each other, parallelize them.

Mistake 3: Not Handling Errors

// ❌ Unhandled rejection
async function saveUser(user) {
  const result = await db.save(user);
  return result;
}

// ✅ Handle the error
async function saveUser(user) {
  try {
    const result = await db.save(user);
    return result;
  } catch (error) {
    console.error('Failed to save user:', error);
    throw error; // re-throw if caller should handle
  }
}

Mistake 4: Async in forEach

// ❌ Doesn't wait for async operations
items.forEach(async (item) => {
  await processItem(item);
});
console.log('Done!'); // Runs before items are processed!

// ✅ Use for...of
for (const item of items) {
  await processItem(item);
}
console.log('Done!'); // Actually done

// ✅ Or Promise.all for parallel
await Promise.all(items.map(item => processItem(item)));
console.log('Done!');

Mistake 5: Mixing Callbacks and Async

// ❌ Confused mixing
async function loadData(callback) {
  const data = await fetch(url);
  callback(data);
}

// ✅ Stay async
async function loadData() {
  const data = await fetch(url);
  return data;
}

Pick one pattern and stick with it.

Mistake 6: await in a Return

// These are equivalent:
async function getUser() {
  return await fetchUser();
}

async function getUser() {
  return fetchUser();
}

The extra await is unnecessary (unless you want try/catch to catch its errors).

Key Takeaways

  • Always handle errors
  • Parallelize when possible
  • Don't use async callbacks with forEach
  • Keep it simple

Back to Journal