React-Query源码探秘 5-Retryer

352 阅读2分钟

专栏目录: 全网最细 React-Query源码探秘 - 不月阳九的专栏 - 掘金 (juejin.cn)

Retryer React-query底层请求方法

  1. 我们在useQuery钩子中配置请求函数,会一层层传递到Retryer中,由它真正发起请求

我们来看一下Query类上的fetch方法 可以看到这里定义了多个请求回调,用来分发action,交给reducer改变Query的状态

创建retryer

 // 创建retryer  发起请求
    fetch(options: QueryOptions): Promise<any> {
        ...
        // 定义retryer的回调  (dispatch一个Action 用来修改Query的状态)
        const onError = (error: Error) => {
            this.dispatch({ type: 'error', error })
        }
        const onSuccess = (data: any) => {
            this.dispatch({ type: 'success', data })
        }
        ...
        // 创建retryer , 保存在Query上
        this.retryer = createRetryer({
            fn: fetchFn,
            onSuccess,
            onError,
            ...
            retry: options.retry, // 重复次数
            retryDelay: options.retryDelay,// 延迟时间
        })

        // 将retryer返回的结果保存 并返回
        this.promise = this.retryer.promise
        return this.promise
    }

本人手写的简易Retryer代码

  1. retryer会创建一个循环请求,模拟了Promise
  2. retryer重新封装了Promise,将Promise的过程打断,在里面插入对应的回调函数(打断并对Promise进行作用域提升,详见另一篇文章)
  3. retryer在请求失败后会重复请求 记录失败次数 并执行对应的回调
  4. 配置了delay后 每次请求失败会通过sleep函数延迟请求
export function createRetryer(config: RetryerConfig) {
    let failureCount = 0
    let isResolved = false   //执行了自定义的res或rej后会改变  之后不会继续执行
    let promiseResolve = (value: any) => { }
    let promiseReject = (value: any) => { }

    //todo 截断promise执行流程
    //outerResolve是Promise的执行器函数  会执行所有的.then中定义的onResolved函数
    const promise = new Promise<any>((outerResolve, outerReject) => {
        promiseResolve = outerResolve
        promiseReject = outerReject
    })

    const resolve = (value: any) => {  // 完成执行resolve  改变状态并返回
        if (isResolved) return
        isResolved = true
        config.onSuccess?.(value)
        promiseResolve(value) // 执行后续.then中定义的onResolve函数
    }
    const reject = (value: any) => {   // 完成执行reject  改变状态并返回
        if (isResolved) return
        isResolved = true
        config.onError?.(value)
        promiseReject(value) // 执行所有.catch中定义的onReject函数
    }

    // 启动retryer会执行run方法   开始查询循环 中途如果出现变化(接收到数据)  返回数据或做其他处理
    const run = () => {
        if (isResolved) return
        let promiseOrValue;
        try {
            promiseOrValue = config.fn()  // Promise.resolve()
        } catch (err) {
            promiseOrValue = Promise.reject(err)
        }

        // 将结果丢入promise继续循环
        Promise.resolve(promiseOrValue)
            .then(resolve) 
            .catch((err) => {
                if (isResolved) return
                retry(err)
            })
    }

    const retry = (error: any) => {
        const retry = config.retry ?? 3
        const retryDelay = config.retryDelay ?? 3000
        const shouldRetry = config.retry === true || failureCount < retry
        // 如果重复次数到上限 或者 配置为false  直接执行reject
        if (!shouldRetry) return reject(error)
        failureCount++
        config.onFail?.(error)

        // 延迟后再次执行请求
        sleep(retryDelay).then(() => {
            run()
        })
    }

    // 开始执行循环
    run()

    return {
        promise
    }
}