0
votes

I am looking for a whenever kind of promise helper. Let's take the Promise.All function. I have 4 promises. Two are instant speed. One is quick. One is slow. The slow promise takes 3 seconds to resolve.

const promise1 = Promise.resolve(3);
const promise2 = new Promise((resolve, reject) => {
  setTimeout(resolve, 3000, 'slow');
});
const promise3 = new Promise((resolve, reject) => {
  setTimeout(resolve, 100, 'foo');
});

Promise.all([promise1, promise2, promise3]).then((values) => {
  console.log(values);
  // here I want to setState()
  // this.setState({values})
});

// output: Array [3, "slow", "foo"]

When I run the code the all is going to wait for all promises (so 3seconds) then display the array. This follows the doc:

The Promise.all() method takes an iterable of promises as an input, and returns a single Promise that resolves to an array of the results of the input promises. This returned promise will resolve when all of the input's promises have resolved, or if the input iterable contains no promises. It rejects immediately upon any of the input promises rejecting or non-promises throwing an error, and will reject with this first rejection message / error.

emphasize is mine

Now what I am looking for is a method who would returned a promise then resolve whenever one of the input's promises have resolved.

Something like:

Promise.whenever([promise1, promise2, promise3]).then((value) => {
  console.log(value);
  // here I want to setState()
  // this.setState({values: this.state.values.concat([value])})
});

who would print

3
foo
slow

promise all

setState

1
So in the end, you don't actually care about aggregation result, you just need those promises to be processed as they fulfill. In this case, the helper you wrote might be just the way to go. - raina77ow
Do you expect the here I want to setState() to be called multiple times? i.e. up to 3 times in your example, one for each resolved promise? - Jaromanda X
@raina77ow basically I am fetching a bunch of resource and I want to display them whenever I can. - aloisdg
@JaromandaX I would like to push to the state. Since the state is immutable, afaik I have to call setState multipletime - aloisdg

1 Answers

1
votes

I didn't find any native whenever, but you can basically build it with a forEach and a higher-order function.

const promise1 = Promise.resolve(3);
const promise2 = new Promise((resolve, reject) => {
  setTimeout(resolve, 3000, 'slow');
});
const promise3 = new Promise((resolve, reject) => {
  setTimeout(resolve, 100, 'foo');
});

const PromiseWhenever = (promises, action, rejectionAction) => {
  promises.forEach(promise => {
    promise.then(action).catch(rejectionAction);
  });
}

PromiseWhenever([promise1, promise2, promise3], value => console.log(value), () => console.error("failed"))

Now if you want Promise.Whenever you will have to edit the Promise's prototype. Is it worth it though?

For the setState, it will works as you expected:

PromiseWhenever([promise1, promise2, promise3], value =>
    this.setState({ values: this.state.values.concat([value]) }, () => console.error("failed"))

Related to How do I resolve multiple promises as they resolve? and setState inside promise.all() react