Promise.all()

Jessica Pamanian
Frontend Weekly
Published in
3 min readNov 8, 2017

I was failing miserably at finding an elegant solution for populating state with data received from a series of consecutive API calls, nine to be exact. It seemed excessive, but surely I couldn’t be the only person ever to need numerous API calls at once — so, how in hell did they do it?

The task was to make a 3 x 3-celled table that would display the lowest monthly rates for plans of $250K, $500K and $1M with terms of 15, 20 and 25 years. The first fetch with query params of 250K and 15 year term returned:

[
{
"name": "pacific",
"monthly": 11.88,
"annual": 142.5,
"amount": 250000,
"term": 15
},
{
"name": "national",
"monthly": 12.02,
"annual": 137.25,
"amount": 250000,
"term": 15
},
{
"name": "banner",
"monthly": 13.78,
"annual": 157.49,
"amount": 250000,
"term": 15
},
...
]

It needed sorting by monthly rate, the lowest of which I’d store in state thusly:

state = {
coverage: {
250000: {
15: {
"name": "pacific",
"monthly": 11.88,
"annual": 142.5,
"amount": 250000,
"term": 15
},
20: {},
25: {}
},
500000: {
15: {},
20: {},
25: {}
},
1000000: {
15: {},
20: {},
25: {}
},
}
}

You get the idea. Though a bit tedious, it seemed pretty simple in theory — fetch, set state, fetch, set state, ad infinitum. I placed all nine consecutive fetches in componentDidMount(). It looked like the most horrific callback-type hell I’d ever seen. I decided to stick it out, get it working and refactor later. Wrong. The second fetch hit me with the first of a series of problems.

When it comes to deep merging of Javascript objects, I’m no master. I tried for what seemed like hours to construct the most elegant function for building a deeply nested object like the one I so desperately needed; no such luck. One or the other values was always missing. I could never get them both at the same time. Then I remembered what makes Javascript like totally the funnest thing in the whole wide world: asynchronicity! There had to be another way…

As I lay in bed that night, I did what I always do when I’m stuck on something and can’t fall asleep: google from my phone in the dark (a.k.a. drop the phone on my face). I searched best practices for setting state with the result of multiple fetches and found something called Promise.all(), which sounded promising.

…and it was:

componentDidMount() {    let fetches = [
fetch.quarterMil15(),
fetch.quarterMil20(),
...
]
Promise.all(fetches)
.then(data => {
let sorted = data.map(d => this.sortByPremium(d))
let lowest = sorted.map(s => s[0])
let quarterMil = lowest.filter(f => f.coverage_amount === 250000)
let halfMil = lowest.filter(f => f.coverage_amount === 500000)
let mil = lowest.filter(f => f.coverage_amount === 1000000)
let newState = Object.assign(
{}, this.state, {
coverage: Object.assign(
{}, this.state.coverage, {
250000: Object.assign({}, quarterMil),
500000: Object.assign({}, halfMil),
1000000: Object.assign({}, mil)
})
})
this.setState({coverage: newState})
})
}

Promise.all() returns an array of nine Promise objects, one for each fetch. Here, I map over the array of response objects (‘data’) and sort the values in each by monthly premium, storing the first item of each array (the cheapest) in an array called ‘lowest’. I then filtered ‘lowest’ by coverage amounts (250K, 500K and 1M) to get the corresponding values for 15, 20 and 25 year terms. Et voila. Update state with a not-so-bad-looking nested Object.assign(). Done.

--

--