vue 3 的 computed 采用“标脏延迟求值”机制,依赖变化时仅标记 _dirty = true 而不立即执行,真正计算发生在首次 .value 访问时,结合依赖追踪与缓存,确保高效响应。

Vue 3 的 computed 不是“一变就算”,而是“一变先标脏,再读才算”。它的缓存机制核心靠一个 _dirty 布尔标志位控制,配合延迟求值和依赖追踪,既保证响应性,又避免无效计算。
依赖变化时只标记“脏”,不立刻执行
当 computed 所依赖的 ref 或 reactive 属性被修改(触发 set),Vue 不会马上运行 getter。而是:
- 找到该 computed 对应的 effect,调用其 scheduler 函数
- scheduler 检查
_dirty:若为false(即当前结果有效),则设为true - 紧接着调用
trigger(computed, 'value', 'set'),通知所有正在依赖这个 computed 的地方(比如模板渲染或另一个 computed)——“你该重新取值了”
真正计算发生在下一次 .value 访问时
只有当你读取 computed.value 时,才会触发实际计算逻辑:
- 先调用
trackRefValue(this),让当前活跃的 effect(如组件渲染)收集对这个 computed 的依赖 - 判断
_dirty === true,若是,则执行this.effect.run()(即重新跑 getter) - 把新结果存入
_value,并重置_dirty = false
多层依赖链也按需更新,不预计算
比如 A 依赖 B,B 依赖 C:
- C 变 → 触发 B 的 scheduler → B._dirty = true
- 后续访问 A.value 时,A 的 getter 中读到 B.value → 此时 B._dirty 为 true,B 先完成计算并返回新值
- A 拿到 B 的新值后继续执行,最终得到 A 的新结果
- 整个过程没有递归、不穿透、不提前触发,完全由“访问驱动”
缓存的本质就是 1 bit + 一次延迟执行
初始 _dirty = true,首次读取时计算并设为 false;之后只要依赖未变,每次读都直接返回 _value。哪怕模板里用了十次同一个 computed,也只算一次。而依赖连变十次,也只标记一次 _dirty = true,不会重复调度。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!










