Vue 的 computed 缓存是响应式系统核心设计,依赖收集→结果缓存→失效更新三步闭环;Date.now()等无法追踪,因不在依赖图中;与methods本质区别在于惰性求值与依赖追踪,性能差异显著。

Vue 的 computed 不是“每次取就重新算”,而是“只在依赖变了才重算”——缓存不是附加功能,是响应式系统的核心设计。
缓存怎么工作的?三步闭环
Computed 的缓存不是简单记个值,而是一套自动维护的响应式流程:
- 依赖收集:首次访问时,Vue 执行 getter,并在执行过程中监听所有读取的响应式数据(比如 ref.value、reactive 对象属性),把它们记为该 computed 的依赖。
- 结果缓存:计算完成后,结果被保存,computed 状态标记为“干净”(clean);后续访问直接返回缓存值,不执行函数。
- 失效与更新:只要任一依赖触发 setter(如 ref.value = newVal),Vue 就把它标记为“脏”(dirty);下次再读取时,才重新执行 getter、更新缓存、再标 clean。
为什么 Date.now() 或 Math.random() 不行?
因为 Vue 只能追踪明确声明的响应式数据。Date.now() 每次调用都返回新值,但 Vue 完全感知不到它“变没变”——它不在依赖图里,computed 就永远不会重算,结果永远卡在第一次的值。
类似情况还包括:
立即学习“前端免费学习笔记(深入)”;
- 普通 const 变量或非响应式对象属性
- props 解构后未用 toRefs 包裹的值
- 异步回调中读取响应式数据(如 setTimeout 里访问 ref),初始依赖收集阶段捕获不到
computed 和 methods 的本质区别
两者都能返回值,但运行逻辑完全不同:
- methods:模板里每渲染一次、每次调用都执行,无条件、无记忆、无依赖判断。
- computed:背后有依赖图、脏检查、惰性求值整套机制;模板里引用 5 次,也只算 1 次(前提是依赖没变)。
比如对 10 万条数据做 filter,methods 在模板中用 5 次就会执行 5 次;computed 只执行 1 次,性能差异非常真实。
缓存失效的常见陷阱
缓存不是铁板一块,写法不当会让它“看不见变化”:
- 在 getter 中修改响应式数据(造成循环依赖或意外触发)
- 解构响应式对象:
const { name } = user→ name 变成普通变量,不再响应;应改用user.name - 数组索引赋值(
arr[0] = x)或直接改 length,Vue 3 对这类操作响应式支持有限,建议用splice或替换整个数组 - 把 computed 结果再用 ref 包裹并赋值,破坏了只读语义,也会干扰缓存逻辑


















