专栏目录: 全网最细 React-Query源码探秘 - 不月阳九的专栏 - 掘金 (juejin.cn)
Retryer React-query底层请求方法
- 我们在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代码
- retryer会创建一个循环请求,模拟了Promise
- retryer重新封装了Promise,将Promise的过程打断,在里面插入对应的回调函数(打断并对Promise进行作用域提升,详见另一篇文章)
- retryer在请求失败后会重复请求 记录失败次数 并执行对应的回调
- 配置了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
}
}