Implement promiseAll — a utility that behaves like native Promise.all for iterables.
Async aggregation is frequently tested in interviews. If you can implement Promise.all correctly, you’ll recognize the same coordination patterns behind Promise.race, Promise.any, and Promise.allSettled.
1) Input
Accept an iterable of items (arrays, Sets, etc.) where each item can be:
a Promise
a thenable (object with then)
a plain value
2) Resolve behavior
Return a Promise that resolves when all items resolve.
Resolve value must be an array of results in the same index order as the input (not completion order).
3) Reject behavior (short-circuit)
If any item rejects, the returned Promise must reject immediately with the same reason.
4) Edge case
Empty iterable resolves immediately with [].
Examples
// Example: Preserves index order (not completion order)const slow =newPromise((r)=>setTimeout(()=>r("slow"),20));const fast =Promise.resolve("fast");promiseAll([slow, fast]).then(value=>{console.log(value);// ["slow", "fast"]});// Example: Treat values / thenables as resolved inputspromiseAll([1,{then:(r)=>r(2)},Promise.resolve(3)]).then(value=>{console.log(value);// [1, 2, 3]});// Example: Works with any iterable (Set example)promiseAll(newSet([Promise.resolve(1),Promise.resolve(2)])).then(value=>{console.log(value);// [1, 2]});// Example: Rejects immediately on first rejectionpromiseAll([Promise.resolve(1),Promise.reject("error"),Promise.resolve(3)]).catch(error=>{console.log(error);// "error"});
Constraints
Must handle any iterable (not just arrays).
Results must be returned in input index order (never completion order).
Reject immediately on the first rejection and forward the same reason.
Values and thenables must be assimilated (treat like resolved promises).
Empty iterable resolves to an empty array immediately.