前端性能优化实战

前端性能优化是提升用户体验的关键,本文介绍几种常用的优化技巧。

加载性能

资源压缩

  • 使用 Gzip/Brotli 压缩
  • 压缩 JavaScript 和 CSS
  • 压缩图片资源

# Nginx 配置 Gzip
gzip on;
gzip_types text/plain text/css application/json application/javascript;
gzip_min_length 1000;

懒加载

// 图片懒加载
const img = document.querySelector('img[data-src]');
const observer = new IntersectionObserver((entries) => {
    entries.forEach(entry => {
        if (entry.isIntersecting) {
            const img = entry.target;
            img.src = img.dataset.src;
            observer.unobserve(img);
        }
    });
});
observer.observe(img);

预加载关键资源

<link rel="preload" href="critical.css" as="style">
<link rel="preload" href="main.js" as="script">
<link rel="preconnect" href="https://api.example.com">

渲染性能

避免强制同步布局

// Bad - 强制同步布局
for (let i = 0; i < elements.length; i++) {
    elements[i].style.width = box.offsetWidth + 'px';
}

// Good - 批量读取后批量写入
const width = box.offsetWidth;
for (let i = 0; i < elements.length; i++) {
    elements[i].style.width = width + 'px';
}

使用 CSS 动画

/* Good - 使用 transform 和 opacity */
.animate {
    transition: transform 0.3s ease;
}
.animate:hover {
    transform: translateX(10px);
}

/* Bad - 触发重排的属性 */
.animate:hover {
    left: 10px;
}

虚拟列表

对于长列表,只渲染可视区域的元素:

class VirtualList {
    constructor(container, itemHeight, totalItems) {
        this.container = container;
        this.itemHeight = itemHeight;
        this.totalItems = totalItems;
        this.visibleCount = Math.ceil(
            container.clientHeight / itemHeight
        );
    }

    render(scrollTop) {
        const startIndex = Math.floor(scrollTop / this.itemHeight);
        const endIndex = startIndex + this.visibleCount + 1;
        // 只渲染 startIndex 到 endIndex 的元素
    }
}

缓存策略

Service Worker

self.addEventListener('fetch', (event) => {
    event.respondWith(
        caches.match(event.request).then((response) => {
            return response || fetch(event.request);
        })
    );
});

HTTP 缓存头

# 静态资源长期缓存
location ~* \.(js|css|png|jpg|jpeg|gif|ico|svg)$ {
    expires 1y;
    add_header Cache-Control "public, immutable";
}

监控与分析

Web Vitals

关注核心指标:

  • LCP (Largest Contentful Paint): < 2.5s
  • FID (First Input Delay): < 100ms
  • CLS (Cumulative Layout Shift): < 0.1

import { getLCP, getFID, getCLS } from 'web-vitals';

getLCP(console.log);
getFID(console.log);
getCLS(console.log);


持续更新中...