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