Lukas Coorek
Lukas Coorek

Reputation: 227

How to implement Promise.race() with async/await

How can I implement Promise.race() method with async and await?

async function promiseRace(promises) {
  const results = [];
  for (const p of promises) {
    await p;
    results.push(p);
  }
  return results[0];
}

I've tried to implement it like above but this doesn't work.

Upvotes: 7

Views: 10373

Answers (6)

chirale
chirale

Reputation: 1709

Why not:

const race = async (promiseArr) => {
    return Promise.race(promiseArr)
}

And inside your async function:

let dayAtTheRace = await race([
    my.promiseFunc(),
    my.wait(10)
])

Upvotes: 1

Josh Hibschman
Josh Hibschman

Reputation: 3714

You can by using a wrapper promise along with async await. In the wrapper promise, protect the resolve/reject so that only the first promise wins.

Promise.race example using async/await:

// Implements promise.race
const race = async (promises) => {
  // Create a promise that resolves as soon as
  // any of the promises passed in resolve or reject.
  const raceResultPromise = new Promise((resolve, reject) => {
    // Keep track of whether we've heard back from any promise yet.
    let resolved = false;

    // Protect the resolve call so that only the first
    // promise can resolve the race.
    const resolver = (promisedVal) => {
      if (resolved) {
        return;
      }
      resolved = true;

      resolve(promisedVal);
    };

    // Protect the rejects too because they can end the race.
    const rejector = (promisedErr) => {
      if (resolved) {
        return;
      }
      resolved = true;

      reject(promisedErr);
    };

    // Place the promises in the race, each can
    // call the resolver, but the resolver only
    // allows the first to win.
    promises.forEach(async (promise) => {
      try {
        const promisedVal = await promise;
        resolver(promisedVal);
      } catch (e) {
        rejector(e);
      }
    });
  });

  return raceResultPromise;
};

// *************
// Test Methods
// *************
const fetch = async (millis) => {
  await waitMillis(millis);
  return 'Async result: ' + millis + ' millis.';
};

const waitMillis = (millis) => {
  return new Promise((resolve) => {
    setTimeout(() => {
      resolve();
    }, millis);
  });
};

const run = async () => {
  let result;

  result = await race([fetch(1), fetch(2), fetch(3)]);
  console.log('Winner', result);

  result = await race([fetch(3), fetch(2), fetch(1)]);
  console.log('Winner', result);

  result = await race([fetch(10), fetch(3), fetch(4)]);
  console.log('Winner', result);
};

run();

Upvotes: 2

Pratibha Thimmoji
Pratibha Thimmoji

Reputation: 7

Here is my solution:

   async function promiseRace(promises) {
  const results = [];
  for (const p of promises) {
    results.push(await p);
  }
  return results[0];
}

Upvotes: -2

Lukas Coorek
Lukas Coorek

Reputation: 227

function promiseRace(promises) {
  return new Promise((resolve, reject) => {
    promises.forEach(async (promise) => {
      try {
        const result = await promise;
        resolve(result);
      } catch (err) {
        reject(err);
      }
    });
  });

Upvotes: 0

Bergi
Bergi

Reputation: 664513

You can't. Just like you cannot implement the Promise constructor using async/await. Remember that await is only syntactic sugar for then calls - and you cannot implement the basic promise combinators using only that.

Upvotes: 6

Jonas Wilms
Jonas Wilms

Reputation: 138267

You can't. When using await you halt execution onto one specific promise. To implement Promise.race manually, you have to fiddle with callbacks:

function race(promises) {
  return new Promise((resolve, reject) => {
     for(const promise of promises)
        promise.then(resolve, reject);
  });
}

Upvotes: 8

Related Questions