async and await: Linear Asynchronous Control FlowThe async and await keywords let you write Promise-based asynchronous code that reads cleanly from top to bottom like synchronous code. Every async function automatically returns a Promise, and await pauses only that function until the awaited Promise settles.
async / await Runs Without Blockingflowchart TD
Call["Call async function loadData()"] --> Pause["await pauses loadData(), yields thread to Event Loop"]
Pause --> Ready["Promise settles"]
Ready --> Resume["Resume loadData() in Microtask Queue"]
While one async function pauses at await, the rest of your web page stays interactive because the main thread keeps handling clicks and rendering frames.
fetch() and Parallel Promise.all() ExampleWrap await calls in try...catch to handle network errors, and check response.ok because fetch() does not reject on HTTP 404 or 500 responses. When two async tasks do not depend on each other, start both together with Promise.all() instead of awaiting sequentially.
async function mockFetch(label, delayMs) {
return new Promise((resolve) => {
setTimeout(() => resolve({ label, ok: true }), delayMs);
});
}
async function loadDashboard() {
try {
// Run independent async calls in parallel for faster load times!
const [user, stats] = await Promise.all([
mockFetch("UserProfile", 20),
mockFetch("LessonStats", 25),
]);
console.log("Dashboard ready:", { user, stats });
} catch (err) {
console.error("Dashboard load error:", err.message);
} finally {
console.log("Hide loading spinner.");
}
}
loadDashboard();
const a = await getA(); const b = await getB(); doubles total waiting time when b does not need a. Use Promise.all([getA(), getB()]).response.ok with fetch(): fetch() resolves normally on HTTP 404 or 500! Always check if (!res.ok) throw new Error(\HTTP ${res.status}`);before callingres.json()`.await inside Array.forEach(): items.forEach(async item => await save(item)) fires everything at once and never waits before continuing. Use for (const item of items) for sequential work or Promise.all(items.map(...)) for parallel work.async function return if you return a plain value like 42?It automatically wraps that value in a resolved Promise, equivalent to Promise.resolve(42). Callers read it with await fn() or fn().then(...).
await at the top level of a file without an async function?Yes, modern ES modules (<script type="module"> and .mjs / ESM Node files) support Top-Level await directly at module scope.
try...catch catch rejected Promises if I forget await?No! If you write return fetchSomething() inside try...catch without await, the function returns the Promise before it rejects, bypassing catch. Always write return await ... inside try...catch.
Sign in to track your learning journey, earn industry-recognized certificates, and join our elite developer community.
Quick Access With
Experiment with the code from this lesson in our interactive playground.