Search code examples
javascriptpromisefetch

Handle first promise first, the rest in order of completion


I need to fetch data from multiple APIs, all of them are pretty slow to return data.

The first API returns base data. This information is not required to call the other APIs, but it is required to process their results. So while I can send out all requests in parallel, I need to process the results of the first request first.

For example, request nr 1 returns after 30 seconds, nr 2 returns after 15 seconds, and nr 3 returns after 60 seconds. This means that after 30 seconds I can process the results of both nr 1 and 2, and after 60 seconds I can process nr 3. I would prefer to be able to process the base information as soon as possible to provide feedback to the user.

How would I do this in JavaScript?

I can use Promise.all to wait with processing until all fetches have completed, but this can potentially take a long time for any result to show. (In my example, 60 seconds.) I can also launch the first fetch by itself and use Promise.all for the rest after the first reply is processed, but that will mean everything else is delayed by the first request (ie, 30 seconds).

I have a feeling the solution is in using async/await, but I can't figure out how.


Solution

  • You seem to be looking for multiple Promise.all calls, each with the base request and one of the other requests.

    const base = baseRequest().then(preprocess);
    Promise.all([
      Promise.all([base, firstRequest()]).then(([baseData, firstData]) => processFirst(baseData, firstData)),
      Promise.all([base, secondRequest()]).then(([baseData, secondData]) => processSecond(baseData, secondData)),
      Promise.all([base, thirdRequest()]).then(([baseData, thirdData]) => processThird(baseData, thirdData)),
      …
    ]).catch(err => {
      // handle (first) error from any of the above
    })
    

    (you can also add individual error handling as you see fit)

    This will fire off all requests at the same time, and call processFirst / processSecond / processThird as soon as the data they require respectively is available. The outer Promise.all will fulfill once all processing is done, you can chain something onto that as well.