vue计算属性缓存本质是依赖收集→dirty标记→惰性求值的闭环机制;仅当依赖变更且被读取时才重算,非响应式数据或异步读取会导致缓存失效。

缓存不是“存住结果”那么简单
computed 的缓存机制本质是按需重算 + 状态标记,不是把值存在某个变量里就完事。它内部维护一个 dirty 标志位,用来判断当前缓存是否还“新鲜”。初始时 dirty = true,表示还没算过或已过期;一旦执行 getter 得到结果,就会把 dirty 设为 false,并把结果存下来。
访问一次,才触发一次判断
computed 是惰性求值的——组件初始化、依赖变更、甚至父组件更新,都不会自动执行它的 getter。只有你在模板中写 {{ myComputed }},或在 JS 里读取 myComputed.value(Vue 3)或 this.myComputed(Options API)时,才会走下面流程:
- 检查 dirty 是否为 false → 是,直接返回上次缓存的值
- 检查 dirty 是否为 true → 是,执行 getter 函数,用新结果覆盖缓存,再设 dirty = false
依赖变了,但不立刻重算
当 firstName 或 count 这类响应式数据被修改时,Vue 会通知所有依赖它的 computed:“你们脏了”。这时只是把它们的 dirty 设为 true,并不运行 getter。真正重算的时机,还是等到下一次被读取时才发生。
比如你在 watch 里改了 this.count,紧接着 console.log(this.doubleCount),这时 doubleCount 才会重新执行;如果之后一直没访问它,哪怕 count 被改了一百次,它也始终不跑函数。
什么情况下缓存会“失灵”
缓存生效的前提是:getter 内部读取的必须是 Vue 能追踪的响应式来源。以下情况会导致依赖未被捕获,从而缓存不更新:
- 用了非响应式数据,比如 Date.now()、Math.random()、this.$refs、普通对象字面量
- 在异步回调里读取响应式数据,例如 setTimeout(() => console.log(this.msg), 100)
- 对 reactive 对象做了整体替换(如 user = {...newUser}),旧响应式连接断开
- 新增了未通过 defineProperty / proxy 拦截的属性(如 obj.newProp = 'x',且 obj 不是 reactive)











