计算属性天然缓存,依赖响应式数据且需显式读取所有影响结果的字段;避免副作用、非响应式依赖及隐式依赖丢失,必要时结合Map手动缓存。

计算属性天然具备缓存能力,只要依赖项不变,就不会重新执行内部逻辑——这是减少昂贵对象属性重复计算最直接、最安全的方式。关键不在于“加缓存”,而在于“让 Vue 正确识别依赖”并“避免意外打破缓存”。
确保依赖是响应式且可追踪的
计算属性只对 响应式数据(ref、reactive、props 中的响应式字段等)做依赖收集。如果昂贵计算依赖的是普通 JS 对象、函数返回值或未被 Vue 包装的值,缓存会失效或根本不会建立。
- ✅ 正确:用
ref或reactive包裹原始数据,再在计算属性中访问其属性 - ❌ 错误:把一个非响应式的
const raw = { id: 1, name: 'a' }直接传入计算逻辑,Vue 无法监听其变化 - ⚠️ 注意:深层嵌套对象中,仅访问
obj.info不代表自动追踪obj.info.title;需显式读取,或用toRefs/unref辅助
避免在计算中引入不可追踪的副作用
计算属性应是纯函数:输入确定、输出确定、无外部状态干扰。一旦内部调用随机函数、Date.now()、Math.random()、API 请求或修改外部变量,缓存就失去意义——因为结果本就不该复用。
- 不要在
computed(() => {...})里发请求或读 localStorage(这些行为应移至 setup 或生命周期中) - 避免在计算中调用会改变响应式状态的方法(如
someRef.value++),这会触发不必要的更新循环 - 若必须基于时间判断,可用
ref(Date.now())作为显式依赖,并在需要时手动更新它
对复杂参数做稳定 key 缓存(适合高开销场景)
当计算逻辑真正昂贵(如深度遍历、正则匹配、JSON 序列化解析),且输入是对象或数组时,可结合 Map 手动管理局部缓存。此时计算属性本身仍是入口,但实际运算由带缓存的函数承担。
- 在
setup()或computed内部声明一个const cache = new Map() - 用可序列化的 key(如
JSON.stringify({ id, type }))或自定义扁平 key(如`${id}-${type}`)查缓存 - 只提取必要字段构造 key,避免把整个大型响应式对象当 key(会触发多余依赖收集)
- 组件卸载前调用
cache.clear(),防止内存泄漏
警惕隐式依赖丢失导致缓存“假命中”
计算属性只会追踪它实际读取过的响应式字段。如果逻辑里有分支(如 if/else)、条件访问或 try/catch,某些路径可能跳过部分依赖,导致缓存未随真实依赖更新。
- 示例:计算属性里写
return condition ? a.value : b.value,那么只有当前分支涉及的依赖会被追踪 - 修改了未被当前路径访问的
c.value,不会触发重算——这不是 bug,而是设计使然 - 解决方法:确保所有影响结果的响应式字段都在计算函数中被显式读取(哪怕只是用于判断)










