Reputation: 10517
Let's boil it down to the minimum.
I have this little component here that fetches data from the server. The diference with this component and any other is that it has to do two AJAX calls. One after the other!
<template>
<div>Easy</div>
</template>
<script>
import axios from 'axios'
let firstFetch = () => {
return axios.get('/first')
}
let secondFetch = () => {
return axios.get('/second')
}
export default {
name: 'p-components-accordion-box',
methods: {
setActive(index) {
this.$emit('setActive', index)
}
},
asyncData({store, route, router}) {
return new Promise((resolve, reject) => {
firstFetch()
.then((result) => {
secondFetch()
.then((result) => {
resolve()
})
.catch((error) => {
throw { url: '/404' };
})
})
.catch((error) => {
throw { url: '/404' };
})
})
}
}
</script>
<style>
</style>
The thing is this works perfect is all requests work. But if something goes wrong and I do:
throw { url: '/404' };
It works perfect in the browser, meaning I go to '/404' but on NodeJS I keep getting this message.
UnhandledPromiseRejectionWarning: Unhandled promise rejection. This error originated either by throwing inside of an async function without a catch block, or by rejecting a promise which was not handled with .catch(). (rejection id: 1)
Has anybody done something similar?
Upvotes: 1
Views: 1269
Reputation: 10517
In the end this seems to work fine. This is no boilerplate but the final code.
Component.vue - asyncData()
asyncData({store, route, router}) {
let data = {
ca: route.params.ca,
province: route.params.province,
locality: route.params.locality,
}
return store.dispatch('FETCH_MAP_COORDINATES_AND_PROPERTIES', data)
.catch(() => {
if (process.browser) {
router.push('/404')
}else{
console.log("beforeThrow1");
throw { url: '/404' };
}
})
}
This is my FETCH_MAP_COORDINATES_AND_PROPERTIES action
let FETCH_MAP_COORDINATES_AND_PROPERTIES = ({commit, dispatch, state}, data) => {
return new Promise((resolve, reject) => {
fetchMapCoordinatesV2(data, state.axios)
.then((result) => {
if (result.status !== 200) {
logger.error({
key: 'src.api.map.fetchMapCoordinates.then.badResponse',
data: result.data
})
reject(result)
}
logger.info({
key: 'src.api.map.fetchMapCoordinates.then',
})
result = result.data
let center = {
lat: result.location.data.geocode.data.lat,
lon: result.location.data.geocode.data.lon
}
let zoom = result.location.data.zoom
commit('SET_PROPERTY_MAP_CENTER', result.location.data.geocode.data )
commit('SET_PROPERTY_MAP_BOUNDS', result.location.data.geocode )
let default_coords = {
ne: {
lat: result.location.data.geocode.data.ne_lat,
lon: result.location.data.geocode.data.ne_lon,
},
nw: {
lat: result.location.data.geocode.data.nw_lat,
lon: result.location.data.geocode.data.nw_lon,
},
se: {
lat: result.location.data.geocode.data.se_lat,
lon: result.location.data.geocode.data.se_lon,
},
sw: {
lat: result.location.data.geocode.data.sw_lat,
lon: result.location.data.geocode.data.sw_lon,
}
}
fetchMapProperties(default_coords, state.axios)
.then((result) => {
logger.info({
key: 'store.actions.map.index.FETCH_MAP_PROPERTIES.then',
data: result.data
})
commit('SET_MAP_PROPERTIES', result.data)
resolve(result.data)
})
.catch((error) => {
logger.error({
key: 'src.api.map.fetchMapProperties.catch',
coords: default_coords,
data: error
})
reject(error)
})
})
.catch((error) => {
logger.error({
key: 'src.api.map.fetchMapCoordinatesV2.catch',
data: error
})
reject(error)
})
})
};
And these are my two fetch methods:
let fetchMapCoordinatesV2 = (data, axios) => {
let query = '';
if (data.ca) query = query + `/${data.ca}`
if (data.province) query = query + `/${data.province}`
if (data.locality) query = query + `/${data.locality}`
logger.info({
key: 'fetchMapCoordinatesV2',
query: query
})
return axios.get(`/locations${query}`)
}
let fetchMapProperties = (coords, axios) => {
return new Promise((resolve, reject) => {
axios.post(`/properties/map`, coords)
.then((result) => {
logger.info({
key: 'src.api.map.fetchMapProperties.then',
coords: coords
})
resolve(result)
})
.catch((error) => {
logger.error({
key: 'src.api.map.fetchMapProperties.catch',
coords: coords,
data: error.response
})
reject(error)
})
});
}
It works great now, if both calls succeed it renders properly and if any http call fails or receives a non 200 status code it renders /404.
Upvotes: 0
Reputation: 5186
Instead of throwing the error inside asyncData
, try to reject the promise:
export default {
name: 'p-components-accordion-box',
methods: {
setActive(index) {
this.$emit('setActive', index)
}
},
asyncData({store, route, router}) {
return new Promise((resolve, reject) => {
firstFetch()
.then((result) => {
secondFetch()
.then((result) => {
resolve()
})
.catch((error) => {
reject()
})
})
.catch((error) => {
reject()
})
})
}
}
Then, whenever you use that method, you can catch and handle the error:
this.asyncData(.....)
.then(.....)
.catch(error => {
throw { url: '/404' }
})
Upvotes: 3