async/await Best Practices in JavaScript
async/await is powerful. Here are the best practices to write clean, efficient async code.
async/await Best Practices in JavaScript
async/await is the cleanest way to write async code. Here are the best practices.
1. Always Handle Errors
async function main() { try { const data = await fetch("/api"); render(data); } catch (err) { handleError(err); } }
2. Use Promise.all for Parallel Operations
const [a, b, c] = await Promise.all([fetchA(), fetchB(), fetchC()]);
3. Use for...of for Sequential await
for (const url of urls) { const data = await fetch(url); process(data); }
4. Do Not Use await in forEach
// bad urls.forEach(async (url) => { await fetch(url); }); // good for (const url of urls) { await fetch(url); }
5. Limit Concurrency for Large Sets
async function batch(items, size, fn) { for (let i = 0; i < items.length; i += size) { await Promise.all(items.slice(i, i + size).map(fn)); } }
6. Use Promise.allSettled for Partial Failure
const results = await Promise.allSettled([fetchA(), fetchB()]); results.forEach((r) => { if (r.status === "fulfilled") handle(r.value); else handleErr(r.reason); });
7. Do Not Fire and Forget
// bad: no error handling fetch("/api"); // good: await and handle await fetch("/api").catch(handleError);
8. Use async/await Over .then Chains
// clean async function main() { const data = await fetch("/api"); const json = await data.json(); render(json); } // less clean fetch("/api").then((data) => data.json()).then((json) => render(json));
9. Use Top-Level await in ES Modules
// module.js (ES module) const data = await fetch("/api"); export default data;
10. Keep async Functions Focused
Each async function should do one thing. Split large functions into smaller ones for readability and testability.
The Takeaway
async/await best practices: always handle errors (try/catch), use Promise.all for parallel, for...of for sequential, never await in forEach, limit concurrency for large sets, use Promise.allSettled for partial failure, do not fire and forget, prefer async/await over .then, use top-level await in ES modules, and keep functions focused.
Always handle errors with try/catch, use Promise.all for parallel operations, for...of for sequential, never await in forEach, limit concurrency for large sets, use Promise.allSettled for partial failure, do not fire and forget, and prefer async/await over .then chains.
Use try/catch around the await calls. If any await rejects, the catch block runs with the rejection reason. try/catch also catches thrown errors inside the try block.
Prefer async/await. It is more readable (looks synchronous), has better stack traces (easier debugging), and works well with loops (for...of with await). Use .then chains only for complex chaining or when async/await is not available.
Batch with Promise.all: process size items at a time. for (let i = 0; i < items.length; i += size) { await Promise.all(items.slice(i, i + size).map(fn)); }. This avoids overwhelming the server or hitting rate limits.
Using await at the top level of an ES module (not inside an async function). Available in ES2022. Useful for initializing modules with async operations. In CommonJS or older environments, wrap in an async function.
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.

