0

Suppose that a is fetched through api y and b is fetched through api z. Both y and z are called once and only once, when a component is mounted. After fetching a and b, I need to reassign a to be g(a,b) where g is some function.

What's the best way to perform this?

I can think of one way: Should I fetch b first and then, when the promise encapsulating b resolves, fetch a. Then, when the promise encapsulating a resolves, reassign a to be some function of a and b. Or I could use Promise.all

PS: More generally, I also need to fetch c through api omega. I need to reassign c to h(g(a,b), c).

Muno
  • 575
  • 2
  • 5
  • 20
  • 2
    Promise.all seems to be good solution for solving this, but you already mentioned it. So what is the question exactly? – gaborp Apr 29 '20 at 21:42

3 Answers3

1

If you know that you will always need to call these 3 APIs and that a failure in any of them I would suggest to use Promise.all to simply get all the data you need for your logic. Something like:

Promise.all([
   fetchY(),
   fetchZ(),
   fetchOmega()
]).then(([a, b, c]) => {
  const aPrime = g(a,b);
  const cPrime = h(aPrime, c);
  // Pass or store aPrime and cPrime as needed
}).catch((error) => {
    console.log(error);
})
Milton
  • 970
  • 4
  • 13
1

If I understand you correct, you should use Promise.all(). Example:

async fetchData1() {
  const response = await axios.get(...) // get data1
  this.setState({data1: response.data})
}

async fetchData2() {
  const response = await axios.get(...) //get data2
  this.setState({data2: response.data})
}

async componentDidMount() {
  await Promise.All([this.fetchData1, this.fetchData2])
  yourFunctionForProcessingData(this.state.data1, this.state.data2)
}
Mikhail Sidorov
  • 1,325
  • 11
  • 15
-1

You can use the following code to only await what's required at a given time so that you don't waste time waiting for something you don't really need to proceed.

componentDidMount(){
    new Promise(async (resolve, reject) => {
        // You don't need result of omega call as of now but no problem in just hitting the api
        let c = fetch(omega).catch(reject);
        // You need the result of both y and z api calls to calculate g(a,b) so await until both calls are complete:
        let [a, b] = await Promise.all([
           fetch(y),
           fetch(z)
        ]).catch(reject);
        a = g(a, b);
        // Now you need result of omega api call so you await c
        await c;
        c = h(a, c); 
        // you have the final result i.e. c here
        resolve(c);
    }).then(result => this.setState({ result }))
      .catch(error => this.setState({ error }));
}
chiragrtr
  • 902
  • 4
  • 6
  • No, [don't do that](https://stackoverflow.com/questions/46889290/waiting-for-more-than-one-concurrent-await-operation), it will lead to unhandled rejections if there's an error in `fetch(omega)` – Bergi Apr 30 '20 at 07:49
  • @Bergi Of course you'll get exceptions without catch blocks. I specifically mentioned I didn't put .catch() blocks to keep code simple. You're gonna need catch for all the calls. Also the question mentions that they actually need to calculcate h(g(a, b), c) so sooner or later, you do need to fetch(omega) – chiragrtr Apr 30 '20 at 13:53
  • Please show how you'd add catch errors - it's important as it is very easy to get wrong with this approach. Also usually you want to fail as soon as there is an error, which this solution can't. – Bergi Apr 30 '20 at 14:34
  • @Bergi I understand your concern that people can get it wrong so I've updated the solution to show how we can catch errors. @All, The main differences in this solution vs keeping all 3 fetch calls in one Promise.all() are: 1) You get to use `a` and `b` as soon as they're available to calculate `g(a, b)` where `g` can be a time consuming synchronous method so you don't want your CPU to be stay idle just because `omega` hasn't resolved. 2) You still get to fail fast i.e. as soon as any api call fails. – chiragrtr Apr 30 '20 at 18:01
  • Uh, well, that *does* look [wrong](https://stackoverflow.com/q/23803743/1048572). (And has syntax errors from `await` in a non-`async` function). If you just wanted to achieve what you've described in the second part of your comment, you should use `Promise.all([Promise.all([getA(), getB()]).then(([a, b]) => g(a,b)), getC()]).then(([o, c]) => h(o, c))` – Bergi Apr 30 '20 at 18:33
  • Nice! That's a much cleaner way to achieve that. I just wanted to highlight that we can start calculation of `g(a,b)` while calling `fetch(omega)` rather than putting all 3 calls in one `Promise.all()`. p.s. I do miss typing `async` all the time only to realise it when I get an error by IDE. No IDE to save me here, ha! Fixed that. – chiragrtr Apr 30 '20 at 19:16