第 19 题:Vue3 性能优化技巧
🎯 一、核心问题
问:在 Vue3 中,如何优化性能?尤其是响应式系统、虚拟 DOM、静态节点、列表渲染等方面。
- 面试官考察你对 Vue3 原理和实战性能优化的理解
🎯 二、优化方法
1️⃣ 响应式优化
-
减少不必要的响应式对象
reactive会递归代理对象,避免对大量静态数据使用 reactive- 对于静态对象,可直接使用普通对象或
readonly
-
使用
shallowReactive/shallowRef- 只对最外层做响应式,减少深层 Proxy 开销
-
避免过度监听
- watch / computed 只监听必要字段
- watchEffect 谨慎使用大对象
-
computed 缓存
- 对计算量大的逻辑使用 computed,避免重复计算
2️⃣ 虚拟 DOM 优化
-
PatchFlag
- 使用模板编译优化,Vue3 自动生成 PatchFlag
- 减少无效 Diff
-
静态节点提升
- 不依赖响应式数据的节点在编译阶段提升
- 避免每次渲染创建 VNode
-
合理使用 key
- 列表渲染用 key 区分节点,优化复用,减少 DOM 移动
3️⃣ 列表渲染优化
-
v-for + key
- 唯一标识元素,提高 Diff 准确性
css<li v-for="item in list" :key="item.id">{{ item.name }}</li> -
虚拟滚动 / 懒渲染
- 大量列表只渲染可视区域,提高渲染性能
- 可使用
vue-virtual-scroller等组件
-
避免嵌套 v-for
- 嵌套循环会产生指数级渲染开销
- 可拆分组件,局部渲染优化
4️⃣ 事件和组件优化
-
v-on / 方法绑定
- 避免在模板中直接写内联函数,导致每次渲染生成新函数
xml<!-- 不推荐 --> <button @click="count++"></button> <!-- 推荐 --> <button @click="handleClick"></button> -
组件拆分 / 懒加载
- 使用
<Suspense>或动态 import 懒加载大型组件
javascriptconst AsyncComponent = defineAsyncComponent(() => import('./MyComponent.vue')) - 使用
🎯 三、综合示例
xml
<template>
<ul>
<li v-for="item in visibleList" :key="item.id">{{ item.name }}</li>
</ul>
</template>
<script setup>
import { ref, computed } from 'vue'
const list = ref([...Array(10000).keys()].map(i => ({ id: i, name: `Item ${i}` })))
// 虚拟滚动或分页,仅显示部分
const visibleList = computed(() => list.value.slice(0, 100))
</script>
- 只渲染 100 条数据,而不是全部 10000 条
- 减少 DOM 数量 → 提升性能
🎯 四、面试官常见追问
追问 1:Vue3 响应式性能比 Vue2 好在哪?
- Proxy 代替 defineProperty
- 深度递归惰性代理,避免初始化成本高
- 精准依赖收集,减少无效 effect 触发
追问 2:静态节点提升与 PatchFlag 怎么协同优化?
- 静态节点 → 减少 VNode 创建和 Diff
- PatchFlag → 减少动态节点 Diff 范围
- 两者结合 → 最大化性能优化
追问 3:大量列表渲染时,Diff 性能瓶颈如何解决?
- 使用 key 优化复用
- 分页 / 虚拟滚动减少渲染节点数量
- 尽量避免嵌套循环
追问 4:computed 和 watch 在性能优化上有什么作用?
- computed → 缓存计算结果,避免重复计算
- watch → 精准监听变化,执行副作用,不触发不必要渲染
追问 5:响应式对象深层次修改会影响性能吗?
- 深层 reactive 会对每层对象递归代理
- 对大对象或数组,建议使用 shallowReactive / shallowRef 或只代理必要层级
🎯 五、一句话总结(面试必背)
Vue3 性能优化核心:精准响应式(Proxy + computed 缓存)、虚拟 DOM PatchFlag + 静态节点提升、列表渲染优化(v-for + key + 虚拟滚动),结合组件拆分与懒加载,实现高效渲染。