Computed卡顿主因是依赖变化时同步执行高开销计算且结果未复用;需通过Performance面板查长任务、禁用对比、避免深层响应式访问、减少新对象返回、评估必要性并加监控。

Computed 卡顿,核心问题不是“用了 computed”,而是它在每次依赖变化时都同步执行了高开销计算,且结果未被有效复用。排查重点是确认计算是否真的必要、是否可缓存、是否被意外高频触发。
看 Performance 面板里的 render/commit 时段
录制一次用户操作(比如点击筛选按钮或输入搜索词),在 Performance 面板中关注:
- 主线程上是否出现 >50ms 的长任务,且调用栈里频繁出现你的 computed 函数名(如 getFilteredItems、buildTree)
- 这些任务是否密集出现在 render 或 commit 阶段——说明计算正挤占渲染时间
- 对比禁用该 computed 后的帧率:临时注释掉模板中对它的引用,再录一次,看 Scripting 时间是否明显下降
检查 computed 是否读取深层响应式对象
Vue 中每访问一层嵌套属性(如 user.profile.settings.theme.color),都会触发一次 getter 拦截。万级列表 + 四层嵌套访问,单次 render 就可能触发数万次响应式追踪。
- 避免在 computed 中反复解构深层结构;改用 setup 里提前解构,或用 computed(() => obj?.a?.b?.c) 替代链式访问
- 对树形、递归类数据,优先转为扁平 Map(new Map())并用 markRaw 包裹,让 computed 只做 O(1) 查询,不参与递归响应式追踪
- 若 computed 返回的是新数组或对象,确保它没在模板中被当作 prop 直接传给子组件——这会触发 React.memo 或 Vue 的 shallowRef 比较失败,导致无效重渲染
验证是否真需要每次重新计算
问自己三个实际问题:
- 这个结果是否会被多次读取?如果是,当前 computed 每次返回新引用,无法跨组件共享,应提取为全局缓存(如 lodash.memoize 或自建 Map 缓存)
- 计算是否依赖实时 DOM 值(如 el.offsetHeight)?这类操作必须移出 computed,改用 onMounted + watch 或 useResizeObserver
- 输入数据是否高频变动(如搜索框输入)?应加节流,或把过滤逻辑移到 watch + debounce 中,而非放在 reactive 依赖链里
用 PerformanceObserver 主动监控
开发环境加入轻量监听,捕获隐性压力:
- 注册 PerformanceObserver 监听 longtask,通过 attribution.scriptURL 定位到具体 computed 所在文件
- 对疑似函数加简易计时:console.time('getFlattenedTree') / console.timeEnd('getFlattenedTree'),观察单次耗时是否超 10ms
- 配合 Vue Devtools 的 Reactivity 标签,看该 computed 的依赖项是否异常频繁变更(比如一个 ref 被无意义地 .value++)



















