Web 性能优化教程 — 让网站飞起来

适用人群:前端/后端开发者
学习时长:约1天
重要程度:★★★★☆(用户体验核心)

一、性能指标

指标说明目标
FCP(首次内容绘制)页面首次显示内容< 1.8s
LCP(最大内容绘制)最大内容元素显示< 2.5s
FID(首次输入延迟)用户首次交互响应< 100ms
CLS(累积布局偏移)页面布局稳定性< 0.1
TTFB(首字节时间)服务器响应时间< 200ms

二、前端优化

2.1 资源优化

<!-- 1. 图片优化 -->
<!-- 使用WebP格式 -->
<img src="image.webp" alt="..." loading="lazy">

<!-- 响应式图片 -->
<img 
  srcset="small.jpg 480w, medium.jpg 800w, large.jpg 1200w"
  sizes="(max-width: 480px) 480px, (max-width: 800px) 800px, 1200px"
  src="medium.jpg"
  alt="..."
>

<!-- 2. CSS/JS压缩 -->
<!-- Vite自动压缩 -->
npm run build

<!-- 3. 代码分割 -->
<!-- Vue Router懒加载 -->
const routes = [
  { path: '/user', component: () => import('./views/User.vue') }
]

<!-- 4. 预加载关键资源 -->
<link rel="preload" href="critical.css" as="style">
<link rel="preload" href="main.js" as="script">

2.2 缓存策略

# Nginx缓存配置
location ~* \.(jpg|jpeg|png|gif|ico|css|js|woff2)$ {
    expires 30d;
    add_header Cache-Control "public, immutable";
}

# HTML不缓存
location ~* \.html$ {
    add_header Cache-Control "no-cache, no-store, must-revalidate";
}

// Service Worker缓存
// sw.js
const CACHE_NAME = 'v1'
const urlsToCache = ['/', '/styles.css', '/script.js']

self.addEventListener('install', event => {
  event.waitUntil(
    caches.open(CACHE_NAME)
      .then(cache => cache.addAll(urlsToCache))
  )
})

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

2.3 渲染优化

// 1. 虚拟列表(大数据量)
// 使用vue-virtual-scroller或react-window

// 2. 防抖和节流
// 搜索防抖
function debounce(fn, delay) {
  let timer
  return function (...args) {
    clearTimeout(timer)
    timer = setTimeout(() => fn.apply(this, args), delay)
  }
}

// 滚动节流
function throttle(fn, delay) {
  let last = 0
  return function (...args) {
    const now = Date.now()
    if (now - last >= delay) {
      last = now
      fn.apply(this, args)
    }
  }
}

// 3. 图片懒加载
// 使用loading="lazy"或Intersection Observer


三、后端优化

3.1 数据库优化

-- 1. 添加索引
CREATE INDEX idx_status ON posts(status);
CREATE INDEX idx_author_status ON posts(author_id, status);

-- 2. 使用EXPLAIN分析
EXPLAIN SELECT * FROM posts WHERE status = 'published' ORDER BY created_at DESC LIMIT 10;

-- 3. 避免SELECT *
SELECT id, title, slug FROM posts WHERE status = 'published';

-- 4. 分页优化
-- 慢:大偏移量
SELECT * FROM posts LIMIT 10 OFFSET 10000;
-- 快:游标分页
SELECT * FROM posts WHERE id > 10000 LIMIT 10;

-- 5. 批量操作
INSERT INTO users (username, email) VALUES
('user1', 'user1@example.com'),
('user2', 'user2@example.com');

3.2 缓存策略

# Redis缓存模式

# 1. Cache-Aside(旁路缓存)
def get_user(user_id):
    # 先查缓存
    cache_key = f"user:{user_id}"
    user = redis.get(cache_key)
    if user:
        return json.loads(user)
    
    # 缓存未命中,查数据库
    user = User.query.get(user_id)
    if user:
        # 写入缓存
        redis.setex(cache_key, 3600, json.dumps(user.to_dict()))
    return user

# 2. Write-Through(写穿透)
def update_user(user_id, data):
    # 更新数据库
    user = User.query.get(user_id)
    user.update(data)
    db.session.commit()
    
    # 更新缓存
    redis.setex(f"user:{user_id}", 3600, json.dumps(user.to_dict()))

# 3. 缓存失效策略
# 设置过期时间
redis.setex(key, 3600, value)  # 1小时过期

# 主动删除
def update_user(user_id, data):
    User.query.get(user_id).update(data)
    redis.delete(f"user:{user_id}")  # 删除缓存

3.3 接口优化

# 1. 响应压缩
from flask import Flask
from flask_compress import Compress

app = Flask(__name__)
Compress(app)

# 2. 分页返回
@app.route('/api/users')
def get_users():
    page = request.args.get('page', 1, type=int)
    size = request.args.get('size', 10, type=int)
    
    # 限制每页数量
    size = min(size, 100)
    
    pagination = User.query.paginate(page=page, per_page=size)
    return jsonify({
        'items': [u.to_dict() for u in pagination.items],
        'total': pagination.total,
        'page': page,
        'size': size
    })

# 3. 字段过滤
@app.route('/api/users')
def get_users():
    fields = request.args.get('fields', '').split(',')
    users = User.query.all()
    
    if fields:
        return jsonify([{k: getattr(u, k) for k in fields if hasattr(u, k)} for u in users])
    
    return jsonify([u.to_dict() for u in users])


四、Nginx优化

# 1. Gzip压缩
gzip on;
gzip_vary on;
gzip_proxied any;
gzip_comp_level 6;
gzip_types text/plain text/css application/json application/javascript text/xml application/xml;

# 2. 连接优化
keepalive_timeout 65;
client_max_body_size 10m;

# 3. 静态文件缓存
location ~* \.(jpg|jpeg|png|gif|ico|css|js|woff2)$ {
    expires 30d;
    add_header Cache-Control "public, immutable";
    access_log off;
}

# 4. 代理缓冲
proxy_buffering on;
proxy_buffer_size 4k;
proxy_buffers 8 4k;


五、监控与分析

// 性能监控
// 1. Web Vitals
import { getCLS, getFID, getLCP } from 'web-vitals'

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

// 2. 性能计时
performance.mark('start')
// ... 执行操作
performance.mark('end')
performance.measure('操作耗时', 'start', 'end')

const measures = performance.getEntriesByName('操作耗时')
console.log(measures[0].duration)


六、优化检查清单

前端
✅ 图片压缩和WebP格式
✅ CSS/JS压缩和代码分割
✅ 路由懒加载
✅ 图片懒加载
✅ 虚拟列表(大数据量)
✅ 防抖和节流
✅ 浏览器缓存

后端
✅ 数据库索引优化
✅ Redis缓存
✅ 响应压缩
✅ 分页查询
✅ 批量操作
✅ 异步处理耗时任务

Nginx
✅ Gzip压缩
✅ 静态文件缓存
✅ 代理缓冲
✅ 连接优化

数据库
✅ 索引设计
✅ 查询优化
✅ 读写分离
✅ 分库分表(大数据量)


学习建议

  1. 先测量再优化,用Lighthouse等工具分析
  2. 优先优化瓶颈,不要盲目优化
  3. 缓存是最有效的优化,合理使用Redis
  4. 数据库优化是核心,索引和查询优化
  5. 持续监控,建立性能监控体系
返回首页