After this lesson you can
- Await a promise and handle its rejection
- Say why a floating promise escapes try/catch
- Run independent work in parallel rather than in sequence
A promise is a value that is not ready yet. await waits for it.
async function load(id: string): Promise<User> {
const res = await fetch(`/api/users/${id}`);
if (!res.ok) throw new Error(`HTTP ${res.status}`);
return res.json() as Promise<User>;
}
An async function always returns a promise, whatever you write inside it.
Returning 5 returns Promise<number>.
The try/catch that never catches
try {
sendWelcomeEmail(user.email); // no await
} catch (err) {
logger.warn(err); // never runs
}
try guards the synchronous execution of its block. The call returns a
promise immediately, the block finishes, and the rejection arrives later
with nothing on the stack to catch it — as an unhandled rejection, which
under Node's default policy takes the process down.
The fix is await. Every promise should be awaited, returned, or explicitly
discarded with a comment saying why it is fire-and-forget. A bare promise
used as a statement always deserves a second look.
Sequential against parallel
const a = await loadUser(id); // waits
const b = await loadOrders(id); // then waits again
Those two do not depend on each other, so waiting twice wastes the first
wait. Promise.all starts both and waits once:
const [a, b] = await Promise.all([loadUser(id), loadOrders(id)]);
Fifty sequential calls at 500 microseconds each is 25 milliseconds of pure waiting. In parallel it is closer to one round trip.
Promise.all rejects as soon as any one rejects. When you want every
result including the failures, Promise.allSettled gives you both.
Try it
function slow<T>(value: T, ms: number): Promise<T> { return new Promise((resolve) => setTimeout(() => resolve(value), ms));} export async function run(): Promise<Record<string, number>> { const sequentialStart = Date.now(); await slow("a", 60); await slow("b", 60); await slow("c", 60); const sequential = Date.now() - sequentialStart; const parallelStart = Date.now(); await Promise.all([slow("a", 60), slow("b", 60), slow("c", 60)]); const parallel = Date.now() - parallelStart; // Rounded to tens of milliseconds so the result is stable to look at. return { sequentialMs: Math.round(sequential / 10) * 10, parallelMs: Math.round(parallel / 10) * 10, };}Try it yourself
2 visible tests · 2 hidden testswait(ms) is given: it resolves to ms after ms milliseconds.
Implement sumDelays(delays: number[]): Promise<number>, which awaits
every one of them and returns the sum. However you write the awaiting,
the sum must come out right — this sandbox checks the answer, not how
long it took.
sumDelays([5,10,15])sumDelays([])
Sign up to check the hidden tests and save your progress. Sign up