Async & Promisesmedium

Implement Promise.any(promises)

Implement `Promise.any` from scratch. It should resolve with the first fulfilled promise and only reject when all promises reject, with an aggregate error.

Asked at Google, Meta, Amazon

#promises#async#concurrency

Answer

function promiseAny(promises) {
  return new Promise((resolve, reject) => {
    if (promises.length === 0) {
      return reject(new AggregateError([], 'All promises were rejected'))
    }

    const errors = new Array(promises.length)
    let rejectedCount = 0

    promises.forEach((p, i) => {
      Promise.resolve(p)
        .then(resolve) // first success wins immediately
        .catch((err) => {
          errors[i] = err
          rejectedCount++
          if (rejectedCount === promises.length) {
            reject(new AggregateError(errors, 'All promises were rejected'))
          }
        })
    })
  })
}

// Usage
promiseAny([
  Promise.reject('fail-1'),
  new Promise((res) => setTimeout(() => res('ok'), 50)),
  Promise.reject('fail-2'),
]).then(console.log) // "ok"

Practise more Async & Promises questions →