一、代码优化
1.1 防抖与节流
| 技术 | 原理 | 应用场景 |
|---|---|---|
| 防抖 | n 秒内只执行最后一次 | 搜索框输入、表单验证 |
| 节流 | n 秒内只执行一次 | 滚动加载、按钮点击、窗口 resize |
// 防抖
function debounce(fn, delay = 300) {
let timer = null
return function (...args) {
if (timer) clearTimeout(timer)
timer = setTimeout(() => fn.apply(this, args), delay)
}
}
// 节流
function throttle(fn, delay = 300) {
let lastTime = 0
return function (...args) {
const now = Date.now()
if (now - lastTime >= delay) {
fn.apply(this, args)
lastTime = now
}
}
}1.2 避免重排重绘
概念
- 重排(Reflow):DOM 结构变化导致的重新布局
- 重绘(Repaint):样式变化但不影响布局
优化方案:
// ❌ 差:多次重排
element.style.width = "100px"
element.style.height = "100px"
element.style.margin = "10px"
// ✅ 好:批量修改
element.style.cssText = "width: 100px; height: 100px; margin: 10px;"
// ✅ 好:使用 DocumentFragment
const fragment = document.createDocumentFragment()
list.forEach((item) => {
const li = document.createElement("li")
li.textContent = item
fragment.appendChild(li)
})
ul.appendChild(fragment)
// ✅ 好:使用 class
element.classList.add("active")
// ✅ 好:脱离流操作
element.style.display = "none"
// 修改
element.style.display = "block"1.3 使用 IntersectionObserver
// 图片懒加载
const observer = new IntersectionObserver((entries) => {
entries.forEach((entry) => {
if (entry.isIntersecting) {
const img = entry.target
img.src = img.dataset.src
observer.unobserve(img)
}
})
})
document.querySelectorAll("img[data-src]").forEach((img) => {
observer.observe(img)
})1.4 使用 requestAnimationFrame
// 动画优化
function animate() {
// 动画逻辑
requestAnimationFrame(animate)
}
requestAnimationFrame(animate)1.5 Web Worker
// 主线程
const worker = new Worker("worker.js")
worker.postMessage(data)
worker.onmessage = (e) => console.log(e.data)
// worker.js
self.onmessage = (e) => {
// 耗时计算
const result = heavyCalculation(e.data)
self.postMessage(result)
}二、网络优化
2.1 请求优化
| 技术 | 说明 |
|---|---|
| 请求缓存 | 利用 Cache-Control、ETag 等 |
| 取消请求 | axios cancelToken / AbortController |
| 请求重试 | 指数退避策略 |
| 请求合并 | 减少 HTTP 请求次数 |
| 并行请求 | Promise.all() |
2.2 压缩与 CDN
// Gzip 配置(Nginx)
// gzip on;
// gzip_types text/plain application/json;
// 图片压缩
// - WebP 格式
// - 响应式图片 srcset
// - 懒加载 loading="lazy"2.3 按需加载
// 路由懒加载
const Home = () => import("@/views/Home.vue")
// 组件懒加载
const HeavyComponent = defineAsyncComponent(() => import("./HeavyComponent.vue"))
// 第三方库按需引入
import { Button, Input } from "element-ui"
// 而非 import ElementUI from 'element-ui'三、首屏优化
3.1 优化清单
| 优化项 | 说明 | 优先级 |
|---|---|---|
| CDN 加速 | 静态资源走 CDN | ⭐⭐⭐ |
| Gzip 压缩 | 减小传输体积 | ⭐⭐⭐ |
| SSR 渲染 | 服务端渲染首屏 | ⭐⭐ |
| 骨架屏 | 减少用户焦虑 | ⭐⭐ |
| 图片懒加载 | 非首屏图片延迟加载 | ⭐⭐⭐ |
| 路由懒加载 | 拆分代码包 | ⭐⭐⭐ |
| 异步加载 | 非关键资源异步 | ⭐⭐ |
| 虚拟滚动 | 长列表优化 | ⭐⭐ |
| Tree-shaking | 去除未用代码 | ⭐⭐⭐ |
| 代码分割 | 拆分 vendor 包 | ⭐⭐⭐ |
3.2 关键渲染路径优化
HTML → DOM
↓
CSS → CSSOM
↓
渲染树 → 布局 → 绘制
优化方案:
- 关键 CSS 内联
- 非关键 CSS 异步加载
- 减少 DOM 层级和数量
- 使用 GPU 加速(
transform、will-change)
四、打包优化
4.1 Webpack 优化配置
// 1. 代码分割
optimization: {
splitChunks: {
chunks: 'all',
cacheGroups: {
vendors: {
test: /[\\/]node_modules[\\/]/,
name: 'vendors',
priority: 10
}
}
}
}
// 2. Tree-shaking
// package.json
{
"sideEffects": false
}
// 3. 压缩
optimization: {
minimize: true,
minimizer: [
new TerserPlugin(), // JS 压缩
new CssMinimizerPlugin() // CSS 压缩
]
}4.2 分析工具
# 打包体积分析
npm install -D webpack-bundle-analyzer
# 打包速度分析
npm install -D speed-measure-webpack-plugin五、事件代理
使用场景
当需要给大量元素绑定相同事件时,使用事件代理可以减少内存消耗
<template>
<ul @click="handleClick">
<li v-for="item in list" :key="item.id">
{{ item.name }}
</li>
</ul>
</template>
<script setup>
function handleClick(e) {
// 使用 closest 或 tagName 判断
const li = e.target.closest("li")
if (li && e.currentTarget === e.target.closest("ul")) {
console.log(li.textContent)
}
}
</script>六、性能指标
6.1 Core Web Vitals
| 指标 | 含义 | 目标值 |
|---|---|---|
| LCP | 最大内容绘制 | < 2.5s |
| FID | 首次输入延迟 | < 100ms |
| CLS | 累积布局偏移 | < 0.1 |
6.2 测量工具
- Lighthouse
- Chrome DevTools Performance
- Web Vitals 扩展