Computed级联更新是按需懒性逐层传播的依赖链:A依赖B、B依赖响应式源,源变化仅标记B为脏,A在下次访问时才触发B求值并更新自身,中间未被读取的计算属性不参与更新。

Computed 级联更新,指的是一个计算属性(A)的 getter 中访问了另一个计算属性(B),而 B 本身又依赖于响应式源(如 ref 或 reactive 数据)。当源数据变化时,B 先被标记为脏,随后 A 在下一次访问时因依赖 B 而重新求值——整个过程不是“立即连环触发”,而是按需、懒性、逐层向下传播的更新链路。
级联依赖的本质是依赖嵌套,不是函数调用链
Vue 并不把 computed(() => a.value + b.value) 和 computed(() => c.value * 2) 当作普通 JS 函数调用关系处理。它通过响应式系统将每个 computed 包装成独立的响应式节点,彼此之间靠“被读取”建立依赖连接:
- 当 A 的 getter 执行时,它读取 B.value → 此刻 Vue 记录“A 依赖于 B”
- B 本身是一个 computed,它有自己的依赖(比如 ref x)和自己的 dirty 标志
- x.value 改变 → 触发 B 的 trigger → B.dirty = true
- 下次访问 A.value 时,发现 B.dirty === true → 先求值 B(并重置 B.dirty = false),再执行 A 的 getter(此时拿到新 B 值)→ A.dirty = false
级联更新不会“穿透式预计算”
即使 A 依赖 B,B 依赖 C,C 依赖 x,x 变化时:
- 只有 C 被标记为 dirty
- B 和 A 仍保持 clean 状态,不重新计算
- 直到模板或逻辑中真正读取 A.value,才依次触发 C → B → A 的求值(且仅一次)
- 中间某层(如 B)若未被任何地方访问,就不会参与本次更新
常见误区:以为 setter 或副作用会打破级联
级联更新只发生在 getter 求值路径上,与 setter 无关;同时必须避免在 getter 中写副作用:
- ✅ 正确:
const total = computed(() => price.value * qty.value)→const withTax = computed(() => total.value * 1.1) - ❌ 错误:
const withTax = computed(() => { api.fetch().then(...); return total.value * 1.1 })—— 请求不会被追踪,缓存导致逻辑错乱 - ⚠️ 注意:如果 total 返回的是对象,
withTax读取的是该对象引用;对象内部属性变化不会通知 withTax 更新(非深层响应式)
调试级联链路的小技巧
开发阶段可用 onTrack 和 onTrigger 查看依赖关系:
-
onTrack(({ key, target, type }) => console.log('tracked', key))—— 看谁被 A 读取了 -
onTrigger(({ key, target, type, oldValue, newValue }) => console.log('triggered by', key))—— 看谁变了导致 A 重新求值 - 配合 Vue Devtools 的“Reactivity”面板,可直观看到 computed 节点之间的依赖箭头


















