Skip to content

响应式实现的优化 Vue3.2 版本

依赖收集的优化

  • 之前每次执行副作用函数 都需要先执行 cleanup 清除依赖 然后在副作用函数执行的过程重新收集依赖
    • 过程涉及大量的对集合 set 对添加和删除操作 存在优化空间
  • 为了减少集合的添加和删除操作 标识了每个依赖集合的状态 比如:新收集的 还是收集过的

设计的全局变量

  • effectTrackDepth
    • 执行 effect函数的深度
  • trackOpBit
    • 标识依赖的收集状态
  • maxMarkerBits
    • 最大标记的位数
  • effectTrackDepth

effect 函数实现优化

  • 内部使用 ReactiveEffect 类创建了 _effect实例 并且让函数返回 runner 指向 ReactiveEffect类的 run 函数
  • 也就是说在执行副作用函数 effect 的时候 实际执行的就是 run 函数
  • 收集的依赖也从 effect 函数 变成了 _effect 对象
  • 当 run 函数执行的时候 cleanup 函数 不是再默认执行 会通过 包装好的函数 fn 执行前 先执行 trackOpBit = 1 << ++effectTrackDepth 记录 trackOpBit
  • 然后看递归的深度是否超过了 maxMarkerBirts 如果超过 执行老的 cleanup 逻辑
  • 没超过 执行 initDepMarkers 给依赖打标记

优化结果

  • 相比于优化前 每次执行 effect 函数 都需要清空依赖 添加依赖的过程
  • 优化后 每次执行 effect 函数 标记依赖的状态 不会重复收集已经收集的依赖 执行 effect 函数之后 还会移除已被收集但在新一轮没有被收集的依赖
  • 优化了减少对于 dep 依赖集合的操作 自然的性能提高了

trackOpBit 的设计

  • 标记依赖的 trackOpBit 每次执行计算的时候采用了 左移运算符 trackOpBit = 1 << ++effectTrackDepth 并且在赋值 的时候做了运算
  • 为什么要这样 ?
    • 因为 effect 执行会有递归的情况 可以通过这种方式记下每个层级的依赖标记情况
  • 在判断 dep 是否已经收集了当前层的依赖 使用了 wasTracked 函数
    • 内部通过 与运算 的结果是否大于 0 来判断当前层级依赖是否已经收集过了

Welcome to the site