0👍
You are executing all promises at the same time. Promise.all
does not execute them in order. The order of the array you pass it is not relevant. It simply resolves when they all finish regardless of order.
The execution happens when you call the functions, which is before you even push them into the array.
If you need to wait for the first to finish before calling the second. You need to call the second inside the first .then
function. For example…
dispatch('utilities/setLoading', true, { root: true }).then(resultOfSetLoading => {
return Promise.all(coins.map(coin => dispatch('createAcqCostConverted', coin)))
}).then(resultOfCreateQcqCostConverted => {
// all createAcqCostConverted are complete now
})
So now, dispatch('utilities/setLoading')
will run first. Then, once complete, dispatch('createAcqCostConverted')
will run once for each coin (at the same time since I used Promise.all
).
I recommend you read up a bit more on how Promise.all works. It is natural to assume it resolves them in order, but it does not.
0👍
This is how I managed to make it work (both for logged off user and logged in user, 2 different approaches) after I read some of you guys replies, not sure if it’s the cleanest approach.
First function:
fetchUserPortfolioCoins({ commit, dispatch, state, rootGetters }) {
const setCoinsPromise = []
let coinsToConvert = null
// start loader in template
dispatch('utilities/setLoading', true, { root: true })
// if user is logged off, use the coins in the state as dispatch param for createAcqCostConverted
if (!rootGetters['auth/isAuthenticated']) setCoinsPromise.push(coinsToConvert = state.userPortfolioCoins)
// otherwise we pass the coins in the DB
else setCoinsPromise.push(Vue.axios.get('/api/coins/').then(response => { coinsToConvert = response.data }))
// once the call to the db to fetch the coins has finished
Promise.all(setCoinsPromise)
// for each coin retrived, create the converted acq cost
.then(() => Promise.all(coinsToConvert.map(coin => dispatch('createAcqCostConverted', coin))))
.then(convertedCoins => {
// finally, set the portfolio coins and portfolio overview values, and stop loader
commit('SET_USER_COINS', { coins: convertedCoins, list: 'userPortfolioCoins' })
commit('SET_USER_PORTFOLIO_OVERVIEW')
dispatch('utilities/setLoading', false, { root: true })
}).catch(err => { console.log(err) })
},
createAcqCostConverted function:
createAcqCostConverted({ dispatch, rootState }, coin) {
const promises = []
// this check is only going to happen for sold coins, we are adding sell_price_converted in case user sold in BTC or ETH
if (coin.sell_currency === 'BTC' || coin.sell_currency === 'ETH') {
const URL = `https://min-api.cryptocompare.com/data/pricehistorical?fsym=${coin.coin_symbol}&tsyms=${rootState.fiatCurrencies.selectedFiatCurrencyCode}&ts=${coin.sold_on_ts}`
promises.push(Vue.axios.get(URL, {
transformRequest: [(data, headers) => {
delete headers.common.Authorization
return data
}]
}))
}
// if user bought with BTC or ETH we convert the acquisition cost to the currently select fiat currency, using the timestamp
if (coin.buy_currency === 'BTC' || coin.buy_currency === 'ETH') {
const URL = `https://min-api.cryptocompare.com/data/pricehistorical?fsym=${coin.coin_symbol}&tsyms=${rootState.fiatCurrencies.selectedFiatCurrencyCode}&ts=${coin.bought_on_ts}`
promises.push(Vue.axios.get(URL, {
transformRequest: [(data, headers) => {
delete headers.common.Authorization
return data
}]
}))
} else {
// if the selected fiatCurrency is the same as the buy_currency we skip the conversion
if (coin.buy_currency === rootState.fiatCurrencies.selectedFiatCurrencyCode) {
promises.push(coin.acquisition_cost_converted = NaN)
// otherwise we create the acq cost converted property
} else promises.push(dispatch('fiatCurrencies/convertToFiatCurrency', coin, { root: true }))
}
return Promise.all(promises)
.then(response => {
if (coin.sell_currency === 'BTC' || coin.sell_currency === 'ETH') {
const value = response[0].data[coin.coin_symbol][rootState.fiatCurrencies.selectedFiatCurrencyCode]
coin.acquisition_cost_converted = value
}
if (coin.buy_currency === 'BTC' || coin.buy_currency === 'ETH') {
const value = response[0].data[coin.coin_symbol][rootState.fiatCurrencies.selectedFiatCurrencyCode]
coin.acquisition_cost_converted = value
}
return coin
})
.catch(err => { console.log(err) })
},
In the second function I didn’t have to adjust much, I just added a “return” for the Promise.all and corrected the if/else to use the response only in specific causes, because the “value” variable generated from the response is valid only in those 2 cases, in the other cases I could simply return the “coin”.
Hope it makes sense, here to explain anything better if needed and/or discuss ways to make this code better (I have a feeling it’s not, not sure why though 😛 )