Skip to content
SDETRole
SDETRole

JavaScript interview question

Compare Promise.all, Promise.allSettled, Promise.race and Promise.any. When would you use each in test code?

intermediate 2–5 yrs #promises#async#concurrency#error-handling

Short answer

Promise.all fulfils with all results or rejects on the first failure. allSettled waits for every promise and reports each outcome. race settles with the first promise to settle, success or failure. any fulfils with the first success and rejects with an AggregateError only if all fail.

Answer

All four take an iterable of promises and return a single promise. They differ in when they settle and what they report.

Method Fulfils when Rejects when Result
Promise.all all fulfil any rejects (immediately) array of values, input order
Promise.allSettled all settle never array of { status, value } / { status, reason }
Promise.race first settles with success first settles with failure that single outcome
Promise.any first fulfils all reject first value, or AggregateError

None of them cancels the other promises. Work that was started keeps running after the combined promise settles. If you need cancellation, pass an AbortSignal to the underlying operations.

Promise.all: parallel setup that must all succeed

const [user, product, coupon] = await Promise.all([
  api.createUser(),
  api.createProduct(),
  api.createCoupon(),
]);

Results arrive in input order, regardless of completion order. If any call fails, await throws that first error and the test stops, which is exactly what you want for mandatory setup. Watch out: the other requests may still succeed, so cleanup must handle partially created data.

Promise.allSettled: cleanup and bulk checks

const results = await Promise.allSettled(
  createdIds.map((id) => api.delete(`/orders/${id}`)),
);
const failures = results.filter((r) => r.status === 'rejected');
if (failures.length) {
  console.warn(`${failures.length} cleanups failed`, failures.map((f) => f.reason));
}

For teardown you want to attempt everything and report what failed, not stop at the first error. It is also useful for health-checking many endpoints and reporting all broken ones at once.

Promise.race: timeouts

function withTimeout(promise, ms) {
  let timer;
  const timeout = new Promise((_, reject) => {
    timer = setTimeout(() => reject(new Error(`Timed out after ${ms}ms`)), ms);
  });
  return Promise.race([promise, timeout]).finally(() => clearTimeout(timer));
}

Clearing the timer matters: otherwise a pending timer can keep a Node process alive or fire after the test ends. Remember that the original operation is not stopped. For fetch, AbortSignal.timeout(ms) is cleaner because it actually aborts the request.

Promise.any: first healthy source

const baseUrl = await Promise.any(
  mirrors.map(async (url) => {
    const res = await fetch(`${url}/health`);
    if (!res.ok) throw new Error(`${url} unhealthy`);
    return url;
  }),
);

Only if every mirror fails does it reject, with an AggregateError whose errors array holds each reason. Promise.any requires ES2021 (Node 15+).

What interviewers look for

  • Correct settle and reject semantics for each, especially race versus any.
  • Concrete testing use cases: parallel setup, resilient cleanup, timeouts.
  • Knowing promises are not cancelled, and mentioning AbortController.
  • Handling partial failure in Promise.all setups.

A strong answer covers

  • Promise.all: all results in order, rejects fast on first failure
  • allSettled: waits for every promise, returns status/value/reason objects
  • race: first to settle, either outcome; typical timeout pattern
  • any: first fulfilment, AggregateError if all reject
  • Notes that other promises keep running; they are not cancelled
Practise answering under time pressure

Type to search across SDETRole.

Full-text search by Pagefind · runs in your browser Open search page →