Vue计算属性缓存机制依赖追踪+脏状态标记+惰性求值:首次访问执行getter并设_dirty=false,依赖变更时重置_dirty=true,后续访问仅当_dirty为true才重算,否则直返缓存值。

Vue 计算属性的缓存不是“记下结果就完事”,而是靠一套联动机制:依赖追踪 + 脏状态标记 + 惰性求值。它只在真正需要时才计算,且只要依赖没变,就绝不重复执行。
依赖追踪:自动知道“谁动了”
当你访问一个计算属性(比如 fullName),Vue 会在执行 getter 的过程中,把里面读取到的所有响应式数据(如 this.firstName、this.lastName)自动记录为它的依赖。
这个过程由 trackRefValue 等内部函数完成,底层依托 Proxy 或 defineProperty 的 get 拦截。一旦这些依赖后续被修改,Vue 就能精准通知该计算属性“你该更新了”。
_dirty 标志位:决定“要不要重算”
每个计算属性内部都维护一个 _dirty 布尔值:
立即学习“前端免费学习笔记(深入)”;
递归分析 Vue 项目组件依赖,从入口文件生成组件层级图,支持 Vue 2/3,输出组件名、文件路径和属性。适用于分析组件结构、排查依赖或了解项目架构。
- 初始为 true,表示还没算过,首次访问必须执行 getter
- 执行完后设为 false,表示当前值是“干净”的、可直接返回
- 一旦依赖变化,响应式系统会把它重新设为 true,下次访问就会触发重算
这个标志就像一个开关,完全绕开了“每次都要判断依赖是否变化”的开销,效率更高。
惰性求值:不访问,就不算
计算属性不会在组件创建时立刻运行。只有第一次通过 .value(组合式 API)或直接使用(选项式 API 模板中)访问它时,才会触发 getter 并缓存结果。
这意味着:
- 模板里没用到的计算属性,永远不会执行
- 条件渲染分支中未激活的部分,其计算属性也不会提前计算
- 避免了无意义的初始化开销,尤其适合复杂逻辑或大数据处理场景
缓存失效的边界:什么情况下不算“依赖没变”?
缓存生效的前提是“依赖项确实是响应式的”。常见失效情况包括:
- getter 中用了非响应式值(如 Date.now()、Math.random()、普通对象属性未被 reactive 包裹)
- 依赖的是外部变量(非 this 上的 data / ref / computed),Vue 无法追踪
- 手动修改了响应式对象的原型或添加了非 reactive 的新属性(如 obj.newProp = 'x' 且 obj 未用 reactive 包装)
- 在 getter 中执行了副作用(如发请求、改 DOM),虽然不影响缓存逻辑,但违背计算属性设计初衷
这些情况会导致计算属性“看起来不更新”,本质是 Vue 根本没把它和任何响应式依赖绑定起来。

















