在 3.5 重构之前,Vue 响应式采用「依赖集合 + 全局调度队列」模型,我们先梳理原生架构无法规避的性能短板,理解版本化重构的设计必要性。
初代响应式基础执行流程回顾
- 依赖收集 track响应式变量被读取时,将当前激活副作用
effect存入变量对应的dep集合; - 更新派发 trigger响应式变量修改时,遍历
dep内全部 effect,推入全局异步更新队列; - 队列刷新 flushJobs微任务阶段遍历队列执行所有副作用,执行前清空队列防止重复执行。
四大底层性能缺陷
全量遍历依赖集合。trigger 触发更新时,会无条件遍历当前变量 dep 内所有副作用,不存在"该副作用无需更新"的快速跳过逻辑。若一个响应式对象被数十个组件、计算属性共享,每次变更都要完整遍历整个 Set 集合,海量依赖场景下遍历开销极高。
重复调度开销。同一帧内多次修改同一响应式变量,会多次向更新队列插入相同 effect,框架依靠队列去重机制兜底,但去重需要额外的 Map 存储标记,频繁变更场景会产生大量无效队列操作。
缓存失效连锁开销。computed 内部依靠脏标记 _dirty 判断是否需要重新计算,但初代架构中 computed 与普通 effect 共用同一套调度逻辑:若多个组件依赖同一个计算属性,底层会重复派发多层依赖更新,形成链式重复遍历。
组件级更新无法截断。父组件、子组件共享响应式数据时,变更会自上而下完整触发所有关联副作用,无法通过版本号快速判断"当前组件依赖未发生变更",即使组件使用的数据未修改,依然要进入调度校验流程。