Skip to content

循环依赖

在复杂的状态中,有时会不经意间会产生循环依赖,这是响应式状态管理中的一个常见问题。 AutoStore提供了相应的循环依赖检测调试跟踪能力功能,帮助开发者发现和解决循环依赖问题。

同步循环依赖检测

构建AutoStore时如果存在循环依赖,会抛出异常,开发者可以通过异常信息快速定位问题。

以下示例中就存在循环依赖,构建store时会抛出异常。

异步循环依赖检测

异步循环依赖就比较麻烦,无法像同步循环一样构建时自动检测。因为异步计算属性的计算函数是异步的,很容易在多个异步计算时形成很复杂的循环调用链。

AutoStore提供了cycleDetect扩展,用来帮助检测异步计算属性的循环依赖。但是由于进行循环依赖检测需要一定的成本开销, 所以该功能是作为一个扩展,需要手动安装。

启用检测

ts
 import { installCycleDetectExtend }  from '@autostorejs/devtools'
 
installCycleDetectExtend({
  onDetected:(paths)=>{
    console.error("发现循环依赖:",paths)
    return 'disable'
  }  
})

示例

由于a,b存在循环依赖,内部会忽略a,b的计算,导致a,b的值为无法计算。

  • 在控制台可以发现发现循环依赖: a->b->a.loading->a.timeout->a.retry->a.error->a.value->a.progress->b.loading->b.timeout->b.retry->b.error->b.value->b.progress->x的信息,这是循环依赖的路径。
  • onDetected回调函数返回disable代表当检测到循环依赖后,会禁用该计算属性,这样就可以避免循环依赖导致的问题。

基本原理

异步循环依赖检测比较复杂,特别是在异步计算属性中,很容易形成很复杂的循环调用链。

循环依赖检测的基本原理如下:

  • 安装cycleDetect扩展后,会对每个异步计算属性的run函数进行包装。
  • 当计算属性第一次运行时,执行store.wath记录侦听所有的get读操作事件。如果存在循环依赖,就会执行计算属性的run函数,从而可以收集到大量的get事件。
  • 当侦听到指定maxOperates数量的get事件后,进行分析,找出事件列表中的循环依赖路径即可。
  • 然后执行onDetected回调函数,由开发者决定如何处理:
    • return 'disable': 代表禁用该计算属性。
    • return 'ignore': 代表忽略
    • 其他会触发错误

配置参数

installCycleDetectExtend具有以下配置参数:

参数 类型 默认值 说明
maxOperates number 200 最大操作数,从开始运行计算函数后,当收集到此数量的操作事件后开如分析。
onDetected (paths:string)=>'disable' | 'ignore' | void - 当检测到循环依赖时的回调函数,返回disable代表禁用该计算属性,返回ignore代表忽略,其他触发错误。