Prompt
Write an async function getUser(id) that awaits fetchUserData(id) (provided — it rejects for id <= 0) and uses try/catch for error handling. If the fetch fails, return a default object { name: 'Guest' }.
Solution
The real ergonomic win of async/await is that try/catch unifies the sync and async failure paths — one construct handles a thrown error and a rejected promise identically, replacing the .catch() chains where errors sail past handlers attached at the wrong level. Under the hood nothing changed about concurrency: an async function always returns a promise (returned values are wrapped in a fulfillment, thrown errors become rejections), and each await suspends the function, yielding to the event loop; the continuation is scheduled as a microtask when the awaited promise settles. Historically this was transpiled as exactly a generator plus a driver loop calling next() with each resolved value — "await is a yield the engine resumes for you" is the accurate mental model.
Returning { name: 'Guest' } from the catch is a deliberate contract: callers always get a user-shaped object, so the failure is absorbed at the boundary that knows the fallback, not re-thrown for every caller to handle.
Red flag: believing try/catch around a real fetch handles server errors. fetch rejects only on network failure — an HTTP 404 or 500 resolves, so without a response.ok check, failed API calls are silently treated as success and your catch block never runs.
Say it: "An async function always returns a promise — throws become rejections — and await suspends into a microtask continuation, so try/catch gives me one error path for sync and async failures alike."