Common async/await Mistakes in JavaScript
async/await has common pitfalls. Here are the mistakes and how to avoid each.
Common async/await Mistakes in JavaScript
async/await is clean but has common pitfalls. Here are the mistakes and how to avoid each.
Mistake 1: Sequential await for Independent Operations
// slow: sequential const a = await fetchA(); const b = await fetchB(); // fast: parallel const [a, b] = await Promise.all([fetchA(), fetchB()]);
Mistake 2: Using await in forEach
// bad: forEach does not await urls.forEach(async (url) => { await fetch(url); }); // good: for...of or Promise.all for (const url of urls) { await fetch(url); }
Mistake 3: Forgetting try/catch
// bad: unhandled rejection async function main() { const data = await fetch("/api"); // if it rejects, unhandled render(data); } // good: try/catch async function main() { try { const data = await fetch("/api"); render(data); } catch (err) { handleError(err); } }
Mistake 4: Not Awaiting a Promise
// bad: fire and forget (no error handling) async function main() { fetch("/api"); // not awaited console.log("done"); // logs before fetch completes } // good: await async function main() { await fetch("/api"); console.log("done"); }
Mistake 5: Awaiting Non-Promises
const x = await 5; // OK (await unwraps non-promises to themselves) `` This is not a mistake (it works), but it is unnecessary. `await` on a non-promise returns the value. It does add a microtask delay, though. ### Mistake 6: Top-Level await (Older Environments) ```js // does not work in older environments (await must be in an async function) const data = await fetch("/api"); // fix: wrap in an async function async function main() { const data = await fetch("/api"); } main(); `` Top-level `await` works in ES modules (ES2022). In CommonJS or older browsers, wrap in an async function. ### Mistake 7: Returning a Promise from async (Unnecessary) ```js // unnecessary: async already wraps the return async function foo() { return Promise.resolve(42); } // simpler async function foo() { return 42; } `` Both work, but the second is cleaner. ### The Takeaway Common `async/await` mistakes: sequential await for independent operations (use `Promise.all`), using `await` in `forEach` (use `for...of`), forgetting `try/catch` (unhandled rejections), not awaiting (fire and forget), top-level `await` in old environments, and returning `Promise.resolve` from an `async` function (unnecessary).
Sequential await for independent operations (use Promise.all), using await in forEach (use for...of), forgetting try/catch (unhandled rejections), not awaiting (fire and forget), top-level await in old environments, and returning Promise.resolve from an async function (unnecessary).
Because forEach does not await the async callback. The loop finishes immediately, and the async callbacks run in parallel in the background. Use for...of for sequential await or Promise.all with map for parallel.
Use Promise.all: const [a, b] = await Promise.all([fetchA(), fetchB()]). Start all promises at once, then await all. This is much faster than sequential await for independent operations.
No, it works. await on a non-promise returns the value itself. But it does add a microtask delay, which is unnecessary. Avoid await on non-promises unless you need the microtask delay.
Yes, in ES modules (ES2022). In CommonJS or older browsers, await must be inside an async function. Wrap your code in an async function and call it: async function main() { ... } main();
Ready to master React completely?
Want to upskill yourself, crack your next interview, and get your dream job? Join our comprehensive course to dive deeper with high-quality video tutorials, solve interview questions, and a premium community.
Master React
Want to upskill yourself, crack your next interview, and get your dream job? Join our comprehensive course.

