Question presented to candidate: "Promise.all takes an array of promises and resolves once every single one of them resolves, or rejects as soon as any one of them rejects. Can you implement a polyfill for it from scratch? Walk me through the edge cases: what happens with plain, non-promise values mixed into the array, an empty array, and how you keep the results in the right order when the promises do not settle in the order they were given."
What a strong answer should cover:
- A new outer Promise wraps the whole operation, resolving only once every item has settled, and rejecting immediately on the first rejection.
- Results must preserve INPUT order, not completion order — each result is written into a pre-sized results array at its own index, never pushed in arrival order.
- Non-promise values (plain numbers, strings, objects) must be wrapped with
Promise.resolve()so they flow through the identical counting logic as real promises. - An empty input array is a genuine edge case that needs an explicit check — without one, a naive implementation can silently never resolve at all.
- A single rejection anywhere calls the outer reject immediately; sibling promises are not cancelled, they simply become irrelevant once the outer promise has already settled.
- A countdown ("remaining") counter, not an array-length comparison, is what correctly handles the fact that settlement happens asynchronously and out of order.
Clarifying questions expected:
- "Should the input accept any iterable, or specifically an array?" — determines whether to normalize with
Array.from()up front. - "Do sibling promises need to be cancelled once the outer promise rejects, or is it fine if they keep running in the background?" — native
Promise.alldoes not cancel them either, so this is worth naming explicitly rather than assuming.
Code / implementation expected: Yes — a full, runnable polyfill plus a real test proving results stay in input order regardless of completion order, and that rejection short-circuits correctly.