JSworkinges2021

Promise combinators

Four ways to wait.

Promise.all, allSettled, race, and any each combine many promises into one β€” but they differ on what counts as done and what counts as failure. Picking the right one is the whole game.

Four combinators, four contracts

Each combinator takes an iterable of promises and returns a single promise, but they settle on different rules. Promise.all waits for every input to fulfil and rejects the instant any one rejects. Promise.allSettled waits for every input to settle and never rejects β€” you inspect each outcome. Promise.race settles as soon as the first input settles, fulfilled or rejected. Promise.any settles with the first input to fulfil, ignoring rejections until none are left.

all β€” fan out, collect, fail fast

Promise.all is the workhorse for parallel work where you need all the results and any failure should abort. It resolves to an array of results in the same order as the inputs, regardless of which finished first. That ordering guarantee is what makes it safe to destructure the result positionally.

allSettled β€” when partial failure is fine

When one slow or broken request shouldn't sink the rest, reach for Promise.allSettled. It resolves to an array of { status: 'fulfilled', value } or { status: 'rejected', reason } objects β€” one per input, in order. Nothing it returns ever rejects, so you handle outcomes by reading status rather than wrapping in try/catch.

race vs any β€” first to settle vs first to succeed

Both resolve on the first input to finish, but race settles on the first to settle (a fast rejection wins and propagates), while any settles on the first to fulfil (rejections are skipped). race is the classic timeout pattern: race real work against a timer that rejects. any is for redundancy: hit three mirrors, take whichever answers first, and only fail if all of them reject β€” in which case you get an AggregateError.

Try it 5 examples

all: fan out and collect

JSintro
Press Run to execute

Promise.all resolves to an array of all three results β€” count: 3 and the three names β€” because every input fulfilled. Mapping over the ids fires all calls before awaiting, so they run concurrently rather than serially.