前端性能优化策略

2026-06-22 · 6 阅读 · 449字
CSSJavaScript性能优化

前端性能优化策略

性能为什么重要

研究表明,页面加载时间每增加 1 秒,转化率下降 7%,用户满意度下降 16%。在移动端,53% 的用户会在 3 秒内关闭加载过慢的页面。性能优化直接影响用户体验和业务指标。

核心性能指标

Web Vitals

  • LCP(Largest Contentful Paint):最大内容绘制,≤2.5s
  • FID(First Input Delay):首次输入延迟,≤100ms
  • CLS(Cumulative Layout Shift):累计布局偏移,≤0.1

其他关键指标

  • TTFB(Time to First Byte):首字节时间,≤800ms
  • FCP(First Contentful Paint):首次内容绘制,≤1.8s
  • TBT(Total Blocking Time):总阻塞时间,≤200ms

加载优化

资源压缩

// Webpack 可使用 TerserPlugin 压缩 JS
// CSS 使用 CssMinimizerPlugin
// 图片使用 imagemin

代码分割

// React 动态导入
const Dashboard = React.lazy(() => import('./Dashboard'));

// Vue 动态导入
const Dashboard = () => import('./Dashboard.vue');

图片优化

<!-- WebP 格式比 JPEG 小 25-35% -->
<picture>
  <source type="image/webp" srcset="image.webp">
  <img src="image.jpg" alt="描述">
</picture>

<!-- 懒加载 -->
<img loading="lazy" src="image.jpg" alt="描述">

<!-- 使用 srcset 提供多尺寸 -->
<img
  src="small.jpg"
  srcset="medium.jpg 768w, large.jpg 1024w"
  sizes="(max-width: 767px) 100vw, 50vw"
  alt="描述"
>

字体优化

/* 使用 font-display 避免字体闪烁 */
@font-face {
  font-family: 'MyFont';
  src: url('/fonts/myfont.woff2') format('woff2');
  font-display: swap; /* 先用后备字体,加载完成后替换 */
}

/* 子集字体只包含需要的字符 */
/* 使用 WOFF2 格式 */

渲染优化

避免布局抖动

/* 为动态内容预留空间 */
.card-image {
  width: 100%;
  aspect-ratio: 16 / 9; /* 固定宽高比 */
  /* 或使用 width + padding-top 的传统方案 */
}

使用 will-change

.animated-element {
  will-change: transform, opacity;
  /* 提前告知浏览器要变化的属性 */
}

减少重排重绘

// 批量修改 DOM,使用 DocumentFragment
const fragment = document.createDocumentFragment();
items.forEach(item => {
  const li = document.createElement('li');
  li.textContent = item;
  fragment.appendChild(li);
});
list.appendChild(fragment);

// 读写分离:避免强制同步布局
// 错误:先读后写交替进行
// 正确:先批量读取,再批量写入

虚拟列表

// 渲染可视区域内的元素,而非全部
// 适用于长列表(数千条以上)
// 库:react-window、vue-virtual-scroller

网络优化

CDN 加速

<!-- 使用 CDN 托管静态资源 -->
<script src="https://cdn.example.com/js/app.[hash].js"></script>

预加载关键资源

<!-- 预加载关键 CSS/字体 -->
<link rel="preload" href="critical.css" as="style">
<link rel="preload" href="/fonts/roboto.woff2" as="font" crossorigin>

<!-- 预连接第三方源 -->
<link rel="preconnect" href="https://api.example.com">

<!-- 预获取下一页 -->
<link rel="prefetch" href="/next-page">

HTTP 缓存

# Nginx 配置示例
location /static/ {
    expires 1y;
    add_header Cache-Control "public, immutable";
}

运行时优化

防抖与节流

// 防抖:连续操作后执行一次
function debounce(fn, delay) {
  let timer;
  return (...args) => {
    clearTimeout(timer);
    timer = setTimeout(() => fn(...args), delay);
  };
}

// 节流:固定频率执行
function throttle(fn, interval) {
  let last = 0;
  return (...args) => {
    const now = Date.now();
    if (now - last >= interval) {
      last = now;
      fn(...args);
    }
  };
}

Web Worker

// main.js
const worker = new Worker('worker.js');
worker.postMessage({ data: largeArray });
worker.onmessage = (e) => console.log(e.data);

// worker.js
self.onmessage = (e) => {
  const result = expensiveCalculation(e.data);
  self.postMessage(result);
};

性能监测

// Performance API
const observer = new PerformanceObserver((list) => {
  for (const entry of list.getEntries()) {
    console.log(`${entry.name}: ${entry.startTime}ms`);
  }
});
observer.observe({ entryTypes: ['largest-contentful-paint', 'layout-shift'] });

// Web Vitals 库
import { getLCP, getFID, getCLS } from 'web-vitals';
getLCP(console.log);
getFID(console.log);
getCLS(console.log);

总结

性能优化是一个持续的过程,建议先测量再优化。使用 Lighthouse 或 WebPageTest 找出瓶颈,制定针对性的优化方案。记住:20% 的优化手段能解决 80% 的性能问题,优先做投入产出比高的优化。