前言
- 常网IT源码上线啦!
- 本篇录入吊打面试官专栏,希望能祝君拿下Offer一臂之力,各位看官感兴趣可移步🚶。
- 有人说面试造火箭,进去拧螺丝;其实个人觉得问的问题是项目中涉及的点 || 热门的技术栈都是很好的面试体验,不要是旁门左道冷门的知识,实际上并不会用到的。
- 接下来想分享一些自己在项目中遇到的技术选型以及问题场景。
真正的贵人,不会给你鱼,甚至都不一定会教你钓鱼,但一定会告诉你"什么是大海"。

一、前言
性能优化看哪些?
页面加载性能
核心指标:LCP(最大内容绘制)<2.5s,FID(首次输入延迟)<100ms
常见的场景:首屏内容可见时间
更新性能
核心指标:用户操作响应速度、视图更新效率
常见的场景:搜索过滤、SPA页面切换、数据驱动UI更新
有哪些工具可以分析分析。
工具类型 | 推荐工具 | 核心功能 |
---|---|---|
生产环境分析 | PageSpeed Insights | 真实用户性能指标分析 |
WebPageTest | 多地点/设备模拟测试 | |
开发阶段分析 | Chrome DevTools Performance | 时间线性能分析 |
Vue专项工具 | Vue DevTools | 组件渲染追踪 |
app.config.performance = true | 启用Vue专属性能标记 |
架构选型策略

包体积压缩三剑客
-
Tree-shaking :确保使用ES模块(如
lodash-es
替代lodash
) -
模板预编译:避免运行时编译(节省14kb+)
-
依赖分析:使用bundlejs.com评估新增依赖成本
代码分割
代码分割是指构建工具将构建后的 JavaScript 包拆分为多个较小的,可以按需或并行加载的文件。
java
// 路由级分割
const UserProfile = () => import('./UserProfile.vue')
// 组件级分割
const HeavyChart = defineAsyncComponent(
() => import('./HeavyChart.vue')
)
可达到按需加载,避免首次加载太多组件(帮助应用暂时略过了那些不是立即需要的功能)
二、运行时更新优化
Props稳定性模式
这个技巧的核心思想就是让传给子组件的 props 尽量保持稳定。
java
// 反模式:activeId变化导致所有列表项更新
<ListItem v-for="item in list" :active-id="activeId" />
// 优化:保持prop稳定
<ListItem
v-for="item in list"
:active="item.id === activeId" // 布尔值更稳定
/>
渲染指令优化
善用v-once和v-memo优化。
java
<!-- v-once:静态内容冻结 -->
<Footer v-once />
<!-- v-memo:复杂列表优化 -->
<div
v-for="item in hugeList"
:key="item.id"
v-memo="[item.id, item.status]"
>
<!-- 复杂子组件 -->
</div>
不可变数据优化
java
// 大型数据使用浅层响应
const bigData = shallowRef({ ... })
// 修改时整体替换
bigData.value = { ...bigData.value, key: newValue }
计算属性高级技巧
java
// 避免返回新对象
const userInfo = computed(() => ({
name: user.value.name,
isVIP: user.value.level > 3
}))
// 手动优化:值相同时返回旧引用
const optimizedInfo = computed((oldValue) => {
const newValue = { /* 计算逻辑 */ }
return isEqual(newValue, oldValue) ? oldValue : newValue
})
watch的优化:
java
// 避免深度监听大型对象
watch(
() => largeObj.value.id, // 只监听必要属性
(newId) => { ... }
)
// 高频操作使用防抖
watch(
searchInput,
debounce((val) => fetchData(val), 300)
)
避免深层侦听
java
watch(
() => state.list,
(newList) => {
// 处理列表变化
},
{ deep: false }
// 明确禁用深层侦听
)
高效的事件侦听器
java
const stop = watchEffect((onCleanup) => {
const timer = setTimeout(doWork, 100)
// 清理函数优化
onCleanup(() => {
clearTimeout(timer)
cleanupResources()
})
})
大型列表
不管一个框架做得再好,一旦遇到大型列表的渲染,必定很慢很卡,这很正常,因为浏览器要渲染这么多的DOM。
但我们可以优化成:只渲染可视区的列表,然后随着滚动慢慢加载替换上来可视区内。
滚动节流:使用 requestAnimationFrame
优化滚动处理
占位符优化:使用骨架屏替代空白区域
动态加载:根据滚动速度预测加载范围
推荐库:
-
通用列表:vue-virtual-scroller
-
网格布局:vue-virtual-scroll-grid
优化禁忌:
-
避免在大型列表中使用深度响应式
-
谨慎使用
v-html
(可能绕过编译优化) -
避免在模板中使用复杂表达式
渐进优化策略
java
// 初始实现
const state = reactive({ bigData: [...] })
// 阶段1:浅层响应
const state = shallowReactive({ bigData: [...] })
// 阶段2:虚拟化展示
<VirtualList :items="state.bigData" />
// 阶段3:按需加载
const visibleData = computed(() =>
state.bigData.slice(virtualStart.value, virtualEnd.value)
)
三、组件设计
层级不要嵌套太多层,如果用循环,更需要注意这点。
java
// 谨慎使用抽象组件
// 在1000项列表中:
<template v-for="item in list">
<!-- 反模式:每项增加1层抽象 -->
<AbstractWrapper>
<ListItem />
</AbstractWrapper>
<!-- 优化:直接渲染 -->
<ListItem />
</template>
每个组件实例消耗≈普通DOM节点的10倍内存。
无渲染组件优化
传统无渲染组件
java
<RenderlessList :items="items" v-slot="{ item }">
<ListItem :item="item" />
</RenderlessList>
优化后:直接使用组合式函数
java
<script setup>
import { useList } from './useList'
const { processedItems } = useList(props.items)
</script>
<template>
<ListItem
v-for="item in processedItems"
:key="item.id"
:item="item"
/>
</template>
至此撒花~
后记
还是想说:避免过度优化,还是要以真实场景决策!
我们在实际项目中或多或少遇到一些奇奇怪怪的问题。
自己也会对一些写法的思考,为什么不行🤔,又为什么行了?
最后,祝君能拿下满意的offer。
我是Dignity_呱,来交个朋友呀,有朋自远方来,不亦乐乎呀!深夜末班车
👍 如果对您有帮助,您的点赞是我前进的润滑剂。
以往推荐
vue2和Vue3和React的diff算法展开说说:从原理到优化策略
玩转Vue插槽:从基础到高级应用场景(内含为何Vue 2 不支持多根节点)
前端哪有什么设计模式(14k+)