1

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?

4

2 回答 2

3

不要在里面抛出错误asyncData,而是尝试拒绝承诺:

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()
            })
        })
    }
}

然后,无论何时使用该方法,都可以捕获并处理错误:

this.asyncData(.....)
    .then(.....)
    .catch(error => { 
        throw { url: '/404' }
    })
于 2018-05-17T17:31:24.527 回答
0

最后,这似乎工作正常。这不是样板,而是最终代码。

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' };
                }
            })
    }

这是我的 FETCH_MAP_COORDINATES_AND_PROPERTIES 操作

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)
        })
    })



};

这是我的两种获取方法:

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)
        })

    });

}

现在它工作得很好,如果两个调用都成功,它会正确呈现,如果任何 http 调用失败或接收到非 200 状态代码,它会呈现 /404。

于 2018-05-18T10:35:42.407 回答