vue3 computed依赖变化时不立即执行getter,而是先标记_dirty=true,待下次访问.value时才重新计算并更新缓存。

当 computed 的某个依赖项(比如一个 ref 或 reactive 对象的属性)发生变化时,它不会立刻重新执行 getter,而是通过一套“标记 + 延迟求值”的调度机制来触发更新。这个过程的核心不是“一变就算”,而是“一变先标脏,再读才算”。
依赖变化 → 标记 dirty = true
computed 内部维护一个 _dirty 标志位,默认为 true(表示初始未计算)。首次访问 .value 时,getter 执行、缓存结果,并把 _dirty 设为 false。之后只要它所 track 的任意响应式依赖发生 set 操作,就会触发对应的 dep(依赖集合)中所有 effect 的 scheduler 回调。而 computed effect 的 scheduler 就是:
- 检查当前 _dirty 状态,若为 false,说明上次结果还有效,此时才设为 true
- 紧接着调用
trigger(computed, 'set', 'value'),通知所有依赖该 computed 的地方(比如渲染 effect 或其他 computed)需要重新取值
再次读取 .value → 触发重新计算
真正执行 getter 是在下一次访问 computed.value 时发生的。此时 get value 方法会:
- 先调用
trackRefValue(this),让当前 activeEffect(比如渲染 effect)收集对这个 computed 的依赖 - 判断 _dirty === true,就执行
this.effect.run()(即重新跑一遍 getter) - 把新结果赋给 _value,并重置 _dirty = false
为什么不能直接执行 getter?
直接执行会造成冗余计算。例如模板里没用到这个 computed,或它只是被另一个未激活的 computed 间接依赖——这些场景都不该浪费 CPU。Vue3 的设计确保:
- 只有被 activeEffect 实际读取时,才会求值
- 依赖变更只做最小标记(_dirty = true),不立即执行逻辑
- 多个依赖连续变更,只会触发一次 dirty 标记,避免重复调度
长依赖链如何处理?
如果 computed A 依赖 computed B,B 又依赖 ref C,那么:
- C 变更 → 触发 B 的 scheduler → B._dirty = true
- 下次访问 A.value 时,A 的 getter 中读取 B.value → 此时 B._dirty 为 true,B 先重新计算,再返回新值
- A 拿到 B 的新值后继续执行,最终完成整条链的按需更新
整个过程没有预计算、不穿透触发、不递归求值,完全由“访问驱动”和“脏位控制”协同完成。











