JavaScript Async/Await Table

PatternCode shapeField note
await fetch(url)const res = await fetch(url)The function PAUSES here - the rest runs as a microtask after the promise settles
sequential awaitsawait a(); await b();Total time = a + b - only correct when b NEEDS a's result
parallel with Promise.allawait Promise.all([a(), b()])Total time = max(a, b) - START both first, then await the pair
try/catch around awaittry { await f(); } catch (e)Rejection becomes a throwable - no .catch chains, normal error flow
allSettledawait Promise.allSettled(ps)Never rejects - inspect each status; the dashboard/retry pattern
Promise.anyawait Promise.any(ps)First FULFILLED wins - mirror of race; loses only if all reject (AggregateError)
top-level awaitawait at module top levelES modules only - callers importing you wait for your setup
floating promisef(); (no await)Fire-and-forget swallows rejections - always await or .catch, even when ignoring
Reference: the MDN async function reference. async/await is promise syntax, not a new mechanism: await pauses the function (the rest resumes as a microtask) and rejection surfaces as a normal exception for try/catch. The performance rule hides in the two middle rows: sequential awaits add latencies, so start independent work FIRST and await together with Promise.all - three sequential one-second fetches take three seconds; started together they take one. Bottom line: await does not make code parallel by itself, it makes asynchronous code READ sequentially - the parallelism is yours to structure, and every floating promise is an error report silently dropped. Related tools: event loop table (where the resumed code actually runs), fetch table (the most-awaited promise in the browser), and error table (what rejection looks like in the console).

async/await is promise syntax, not a new engine: await pauses the function until the promise settles (the rest resumes as a microtask), and a rejection surfaces as a plain exception you catch with try/catch. The mechanism is the event loop's; the readability is the syntax's.

Bottom line: await does not create parallelism - it makes asynchronous code READ sequentially. Three one-second fetches awaited one after another take three seconds; started together and awaited with Promise.all they take one. The parallelism is yours to structure: start independent work first, await the bundle second.

The honest part: every promise you do not await (or .catch) is a floating promise - if it rejects, nothing handles it and the error is silently dropped, surfacing only as an unhandledrejection console line in production, long after the code that caused it has moved on.

How to use

  1. Sequence only real dependencies: await getUser() BEFORE await getOrders(user.id) - but fetch dashboard widgets together with Promise.all.
  2. Handle rejection with normal flow: wrap awaits in try/catch, and put the try around the SMALLEST block that can fail so the fallback is precise.
  3. Audit for floating promises: any async call without await or .catch is a dropped error report - lint rules like no-floating-promises catch what review misses.

Frequently asked questions

Does await make my code run in parallel?

No - it makes it pause. The parallelism decision happens at the START of the work, not the await: calling two async functions immediately runs both bodies concurrently up to their first await, and THEN awaiting their promises collects results. Sequential awaits (await a(); await b();) force b to start only after a finishes, so latencies add. Promise.all([a(), b()]) runs the cost as the slower of the two. Rule of thumb: dependencies get sequential awaits, independent work gets started together and awaited together.

How is Promise.all different from Promise.allSettled?

Promise.all is fail-fast: the first rejection rejects the whole bundle, and you lose the results of everything that succeeded - right for 'all inputs required' paths like loading a page's critical data. Promise.allSettled never rejects; it resolves with a status list ({status: 'fulfilled', value} or {status: 'rejected', reason}) so you can render successes and retry failures independently - right for dashboards, widgets and any mix where one failure should not blank the page. Choosing between them is really choosing whether a partial result is acceptable.

What is a floating promise and why does it matter?

An async call whose promise is neither awaited nor .catch-ed. The function keeps running, but if the promise rejects, nobody handles the rejection - the error vanishes into an unhandledrejection event, production telemetry sees a symptom far from the cause, and users see a silent failure. It usually comes from treating async functions as fire-and-forget (f(); without await). The discipline: every promise is either awaited, explicitly caught, or deliberately marked as background work with a comment and a top-level .catch that reports.

When do I need Promise.race versus Promise.any?

Promise.race settles with the FIRST settled promise, fulfilled OR rejected - the timeout pattern lives here: race(fetch, timeout(5000)) means a slow request loses to your timer. Promise.any waits for the first FULFILLED promise and ignores rejections along the way - mirror-to-mirror retries live here: ask three mirrors, take whichever answers first; it rejects only when all reject (with an AggregateError listing every failure). Race adopts any outcome; any holds out for a success - picking the wrong one turns your retry logic into an error amplifier.

Related tools