Vue超详细讲解重试机制示例

重试指的是当加载出错时,有能力重新发起加载组件的请求。

异步组件加载失败后的重试机制,与请求服务端接口失败后的重试机制一样。所以,先来讨论接口请求失败后的重试机制是如何实现的, 为此,需要封装一个fetch函数,用来模拟接口请求:

function fetch(){
        return new Promise((resolve,reject) => {
                // 请求会在1秒后失败
                setTimeout(()=>{
                        reject('err')
                },1000)
        })
}

为了实现失败后的重试,需要封装一个load函数,如下面代码所示:

// load函数接收一个onError回调函数
function load(onError){
        // 请求接口,得到Promise实例
        const p = fetch()
        // 捕获错误
        return p.catch(err=>{
                // 当错误发生时,返回一个新的Promise实例,并调用onError回调
                // 同时将retry函数作为onError回调的参数
                return new Promise((resolve,reject)=>{
                        // retry函数,用来执行重试的函数,执行该函数会重新调用load函数并发送请求
                        const retry = () => resolve(load(onError))
                        const fail = () => reject(err)
                        onError(retry, fail)
                })
        })
}

load函数内部调用fetch函数来发送请求,并得到一个Promise实例,并把该实例的resolve

和reject方法暴露给用户,让用户来决定下一步应该怎么做。这里,将新的Promise实例的resolve和reject分别封装为retry函数和fail函数,并将它们作为onError回调函数的参数。

这样,用户就可以在错误发生时主动选择重试或直接抛出错误。

下面的代码展示了用户时如何进行重试加载的:

// 调用load函数加载资源
load(
        // onError回调
        (retry) => {
                // 失败后重试
                retry()
        }
).then(res=>{
        // 成功
        console.log(res)
})

基于这个原理,就可以很容易地将其整合到异步组件的加载流程中,具体实现如下:

function defineAsyncComponent(options){
        if(typeof options === 'function'){
                options = {
                        loader: options
                }
        }
        const {loader} = options
        let InnerComp = null
        // 记录重试次数
        let retries = 0
        // 封装load函数用来加载异步组件
        function load(){
                return loader()
                                .catch((err)=>{
                                        // 如果用户指定了onError回调,则将控制权交给用户
                                        if(options.onError){
                                                return new Promise((resolve,reject) => {
                                                        // 重试
                                                        const retry = () => {
                                                                resolve(load())
                                                                retries++
                                                        }
                                                        // 失败
                                                        const fail = () => reject(err)
                                                        // 作为onError回调函数的参数,让用户来决定下一步怎么做
                                                        options.onError(retry, fail, retries)
                                                })
                                        }else{
                                                throw error
                                        }
                                }
        }
        return {
                name: 'AsyncComponentWrapper',
                setup(){
                        const loaded = ref(false)
                        const error = shallowRef(null)
                        const loading = ref(false)
                        let loadingTimer = null
                        if(options.delay){
                                loadingTimer = setTimeout(()=>{
                                        loading.value = true
                                }, options.delay);
                        }else{
                                loading.value = true
                        }
                        // 调用load函数加载组件
                        load()
                                .then(c=>{
                                        InnerComp = c
                                        loaded.value = true
                                })
                                .catch((err)=>{
                                        err.value = err
                                })
                                .finally(()=>{
                                        loading.value = false
                                        clearTimeout(loadingTimer)
                                })
                        // 省略部分代码
                }
        }
}

原文地址:https://blog.csdn.net/loyd3/article/details/127787998