How to handle promises as they resolve?

Currently, this code print out a zero, because the first promise in the array resolves immediately.

const promises = [];
const promiser = (number) => new Promise((resolve, reject) => window.setTimeout(() => resolve(number), number * 100));
for (let index = 0; index < 10; index++) {
  const promise = promiser(index);
  promises.push(promise);
}

Promise.race(promises).then(r => console.debug(r));

I'm looking to make it so that once the quickest promise resolves, it is removed from the promises array and a new Promise.race call is made with the remaining promises, repeating until no promise is left.

Since Promise.race returns the result of the promise, not the resolved promise itself, though, I am unable to identify which promise was it that resolved and I do not know which one to remove from the array. Is there a way to know this? I suppose I could return a complex object with some sort of a correlation key and the result, but that seems weird. I was hoping second parameter of the Promise.race callback would be index of the promise, but that's not the case and it doesn't make sense either since the then is just a then of another promise, so how would it know that it should return some index anyway. Can you think of a better way?

Also, I run all the promises with the first race, but that shouldn't be a problem for subsequent races, right? In case another promise resolved in the meantime before the subsequent race call was made, it should just return it, no problem, correct? And if multiple promises did resolve in the meantime, it would just return the first (in array order or in resolution order?) and then the next race would return the second and so on… Right?

BTW I also though I could walk the array and remove promises that have isResolved, but that's not a real thing. Even if it was, though, this would completely break for the case where multiple promises resolve between the calls to race.

Upvotes: 3

Views: 1365

Answers (2)

Mattias Buelens
Mattias Buelens

Reputation: 20159

I'm looking to make it so that once the quickest promise resolves, it is removed from the promises array and a new Promise.race call is made with the remaining promises, repeating until no promise is left.

Why do you want to use Promise.race if you eventually want to handle all promises? Can't you simply process every promise as soon as it resolves, and then wait until all promises have been processed?

const promises = [];
const promiser = (number) => new Promise((resolve, reject) => window.setTimeout(() => resolve(number), number * 100));

for (let index = 0; index < 10; index++) {
  const promise = promiser(index)
      .then(r => process(r)); // process every promise individually
  promises.push(promise);
}

Promise.all(promises) // wait for all promises to be processed
       .then(r => console.debug('all done!'));

Or is process also asynchronous, and you need to ensure that only one promise is getting processed at a time?

Upvotes: 5

Ivan Drinchev
Ivan Drinchev

Reputation: 19581

You can return an identifier to the promises

const promises = [];
const promiser = (number, id) => new Promise((resolve, reject) => window.setTimeout(() => resolve({ number, id }), number * 100));
for (let index = 0; index < 10; index++) {
  const promise = promiser(index, "id_" + index);
  promises.push(promise);
}

Promise.race(promises).then(r => console.debug(r.id));

Anyway if you are working with a promise library such as bluebird you can find some utility that can help you structure your code better ( like Promise.reduce or Promise.any )

Upvotes: 1

Related Questions