数据状态关系
组件内状态和缓存数据是双向数据绑定的关系
全局状态
- CONCURRENT_PROMISES, 当前正在进行中的请求
- CONCURRENT_PROMISES_TS,当前正在进行中的请求的开始时间
- FOCUS_REVALIDATORS,窗口聚焦时,需要触发的事件队列
- CACHE_REVALIDATORS,缓存更新时,需要触发的事件队列
- MUTATION_TS
- cache
全局方法
trigger(_key, shouldRevalidate = true)
_key序列化为key 从CACHE_REVALIDATORS获取与key对应的updaters,从cache中取出与key对应的currentData/currentError,遍历updaters,调用updater(shouldRevalidate, currentData, currentError, i>0)
broadcastState(key, data, error)
从CACHE_REVALIDATORS中获取与key对应的updaters,遍历updaters,调用updater(false, data, error)
mutate(_key, _data, shouldRevalidate = true)
_key序列化为key data为undefined, 调用trigger(_key, shouldRevalidate) MUTATION_TS[key] = Date,now() - 1 根据_data的类型做处理,最后获得数据data data !== undefined, cache.set(key, data, false) 从CACHE_REVALIDATORS中获取与key对应的updaters,遍历updaters,调用updater(!!shouldRevalidate, data, error, i > 0)
useSWR内部方法
dispatch(payload)
使用payload更新stateRef 根据stateDependencies中对应key值的true/false,决定是否重新渲染 shouldUpdateState || config.suspense,重新渲染
boundMutate(data, shouldRevalidate)
内部调用mutate(key, data, shouldRevalidate),指定key值mutate
revalidate(revalidateOpts: { retryCount?: number, dedupe?: boolean})
核心逻辑,根据dedupe决定并行请求策略: dedupe = true
- 忽略此次发起的请求,设置startAt为进行中请求的开始时间,
- newData为进行中请求的响应结果
dedupe = false
- 如果存在进行中的请求,在MUTATION_TS中记录当前时间
- 处理loading
- 调用fn,并赋值到CONCURRENT_PROMISES[key]
- 设置startAt为当前时间,并赋值给CONCURRENT_PROMISES_TS[key]
- 赋值newData
- 设置定时器,dedupingInterval时间后,清除CONCURRENT_PROMISES[key]和CONCURRENT_PROMISES_TS[key]
- 调用onSuccess函数
判断MUTATION_TS[key],如果存在且比startAt大,则设置isValidating为false,并放弃对结果的处理。(注意连续2次触发revalidate的时间间隔小于1ms,可能会导致响应覆盖的情况 req1 - 5s - res1/req2 - 3s - res2,这种情况下,res1会覆盖res2)
将newData存入到缓存,keyErr对应的缓存设置为undefined 一系列对状态的判断,dispatch(newState) 根据shouldDeduping决定是否执行broadcastState(key, newData, err);
错误处理
- 保存错误信息到缓存
- 更新state
- 根据shouldDeduping决定是否调用broadcastState(key, undefined, err)
- 调用onError方法
- 错误时重试策略
设置loading为false。
onMounted处理
- 初始化数据,优先取缓存
- 定义softeRevalidate, 默认dedupe = true 调用revalidate
- 有条件的,执行自动revalidate,此处做了一个优化:优先使用requestIdleCallback调用softRevalidate。
- 对softRevalidate进行节流处理,加入 FOCUS_REVALIDATORS[key]的队列中
- 定义onUpdate函数,用于缓存数据更新时,触发组件内部状态更新
- 将onUpdate添加到CACHE_REVALIDATORS[key]的队列中
- 定义清除工作
轮询相关处理
- 定义tick,用于调用revalidate方法
- 根据config.refreshInterval的值,判断是否需要轮询 这里有个坑,如果定义revalidateOnMount为false,但是定义 refreshInterval为2000,依然会自动触发请求
非Suspense返回
- 定义state = { revalidate, mutate, boundMutate}
- 定义error, data, isValidating为state的访问器属性,用来捕获依赖(妥妥的vue实现)
config.ts做了什么?
- 定义全局cache
- 定义全局状态管理
- 定义默认参数
- 监听窗口显示/隐藏/聚焦事件