Step 1 of 5 · Reading · ~3 min
Learn
Async JavaScript
Promise Patterns
You now have promises and async/await. This lesson collects the shapes that real code repeats: wrapping old callback APIs, timeouts, doing things one by one versus all together, collecting failures, and limiting how many things run at once. By the end you can pick the right one for a job and avoid the usual traps.
Wrap a callback API (promisify)
Older Node functions take a callback (err, result) as their last argument. Wrap one in a promise by calling reject for the error and resolve for the result:
Node's util.promisify(legacyHalf) builds exactly this wrapper for any function that follows the (err, result) convention.
A timeout with Promise.race
Promise.race settles like whichever input settles first, so racing a slow operation against a timer that rejects gives a timeout:
The loser is not cancelled. The slow operation keeps running and its result is thrown away, and the timer stays pending. A promise cannot be cancelled; you can only stop waiting for it.
One at a time, or all together
Use for...of with await when each step needs the previous one, or when order and load matter. Start everything first and wait once when the pieces are independent:
Promise.all fails fast: the first rejection rejects the whole thing and you lose the other results. When you want every outcome, use Promise.allSettled, which reports a status for each, and then split them:
Limiting concurrency
Promise.all(thousandItems.map(fetchOne)) starts a thousand operations at once, which can exhaust sockets, memory or a server's patience. You want at most N running together, and as soon as one finishes the next should begin. The tempting version works in batches:
It respects the limit but wastes time. Each batch waits for its slowest member, so with a batch of four where one job takes ten seconds, three slots sit idle for nine of them. A better design keeps every slot busy: finishing one job immediately frees a slot for the next one. Building that is this lesson's exercise.
Common mistakes
- Calling
rejectorresolveand then continuing to run code in the executor. Addreturn. - Reaching for
Promise.allwhen you need every result, then losing them all to one failure. - Thinking a timeout cancels the work. It only stops you waiting.
- Awaiting inside a plain loop when the calls are independent, which serialises them.
- Collecting results in the order jobs finish instead of the order they were given.
Your exercise
Write mapLimit(items, limit, fn): at most limit calls in flight, results in input order, no idle slots. The starter times the run on a virtual clock so you can see the difference.
Discussion
Ask a question, share an insight, or help someone who’s stuck.
Sign in to post a comment or reply.
Loading…