返回博客列表
性能优化

Web 性能监控与优化

2025-08-28
14 分钟阅读
性能优化监控Web
Web 性能监控与优化

Web 性能监控与优化

Web 性能直接影响用户体验和业务指标。建立完善的性能监控体系,持续优化应用性能,是现代 Web 开发的重要任务。

性能指标

1. 核心 Web 指标 (Core Web Vitals)

// 测量 LCP (Largest Contentful Paint)
const observer = new PerformanceObserver((list) => {
  const entries = list.getEntries()
  const lastEntry = entries[entries.length - 1]
  console.log('LCP:', lastEntry.startTime)
})

observer.observe({ entryTypes: ['largest-contentful-paint'] })

// 测量 FID (First Input Delay)
const fidObserver = new PerformanceObserver((list) => {
  const entries = list.getEntries()
  entries.forEach(entry => {
    console.log('FID:', entry.processingStart - entry.startTime)
  })
})

fidObserver.observe({ entryTypes: ['first-input'] })

// 测量 CLS (Cumulative Layout Shift)
let clsValue = 0
const clsObserver = new PerformanceObserver((list) => {
  for (const entry of list.getEntries()) {
    if (!entry.hadRecentInput) {
      clsValue += entry.value
    }
  }
  console.log('CLS:', clsValue)
})

clsObserver.observe({ entryTypes: ['layout-shift'] })

2. 自定义性能指标

// 页面加载时间
const pageLoadTime = performance.timing.loadEventEnd - performance.timing.navigationStart
console.log('页面加载时间:', pageLoadTime)

// 首屏渲染时间
const firstPaint = performance.getEntriesByType('paint')[0]
console.log('首屏渲染时间:', firstPaint.startTime)

// 资源加载时间
const resources = performance.getEntriesByType('resource')
resources.forEach(resource => {
  console.log(`${resource.name}: ${resource.duration}ms`)
})

性能监控工具

1. 自定义监控

class PerformanceMonitor {
  constructor() {
    this.metrics = {}
    this.init()
  }
  
  init() {
    // 监听页面加载完成
    window.addEventListener('load', () => {
      this.collectMetrics()
    })
    
    // 监听页面卸载
    window.addEventListener('beforeunload', () => {
      this.sendMetrics()
    })
  }
  
  collectMetrics() {
    // 收集性能指标
    this.metrics = {
      // 页面加载时间
      pageLoadTime: performance.timing.loadEventEnd - performance.timing.navigationStart,
      
      // DNS 查询时间
      dnsTime: performance.timing.domainLookupEnd - performance.timing.domainLookupStart,
      
      // TCP 连接时间
      tcpTime: performance.timing.connectEnd - performance.timing.connectStart,
      
      // 请求响应时间
      requestTime: performance.timing.responseEnd - performance.timing.requestStart,
      
      // DOM 解析时间
      domParseTime: performance.timing.domContentLoadedEventEnd - performance.timing.domLoading,
      
      // 首屏渲染时间
      firstPaint: this.getFirstPaint(),
      
      // 最大内容绘制时间
      lcp: this.getLCP(),
      
      // 首次输入延迟
      fid: this.getFID(),
      
      // 累积布局偏移
      cls: this.getCLS()
    }
  }
  
  getFirstPaint() {
    const paintEntries = performance.getEntriesByType('paint')
    const firstPaint = paintEntries.find(entry => entry.name === 'first-paint')
    return firstPaint ? firstPaint.startTime : 0
  }
  
  getLCP() {
    return new Promise((resolve) => {
      const observer = new PerformanceObserver((list) => {
        const entries = list.getEntries()
        const lastEntry = entries[entries.length - 1]
        resolve(lastEntry.startTime)
      })
      observer.observe({ entryTypes: ['largest-contentful-paint'] })
    })
  }
  
  getFID() {
    return new Promise((resolve) => {
      const observer = new PerformanceObserver((list) => {
        const entries = list.getEntries()
        entries.forEach(entry => {
          resolve(entry.processingStart - entry.startTime)
        })
      })
      observer.observe({ entryTypes: ['first-input'] })
    })
  }
  
  getCLS() {
    let clsValue = 0
    const observer = new PerformanceObserver((list) => {
      for (const entry of list.getEntries()) {
        if (!entry.hadRecentInput) {
          clsValue += entry.value
        }
      }
    })
    observer.observe({ entryTypes: ['layout-shift'] })
    return clsValue
  }
  
  sendMetrics() {
    // 发送指标到监控系统
    fetch('/api/metrics', {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify({
        ...this.metrics,
        url: window.location.href,
        timestamp: Date.now(),
        userAgent: navigator.userAgent
      })
    })
  }
}

// 初始化监控
const monitor = new PerformanceMonitor()

2. 第三方监控工具

// 使用 Google Analytics
gtag('config', 'GA_MEASUREMENT_ID', {
  custom_map: {
    'custom_parameter_1': 'page_load_time',
    'custom_parameter_2': 'first_paint'
  }
})

// 发送自定义指标
gtag('event', 'page_performance', {
  page_load_time: pageLoadTime,
  first_paint: firstPaint,
  lcp: lcpValue
})

// 使用 Sentry 监控错误
Sentry.init({
  dsn: 'YOUR_DSN',
  integrations: [
    new Sentry.BrowserTracing({
      tracingOrigins: ['localhost', 'your-domain.com']
    })
  ],
  tracesSampleRate: 1.0
})

性能优化策略

1. 资源优化

// 图片懒加载
class LazyImageLoader {
  constructor() {
    this.observer = new IntersectionObserver(this.handleIntersection.bind(this))
    this.images = document.querySelectorAll('img[data-src]')
    this.images.forEach(img => this.observer.observe(img))
  }
  
  handleIntersection(entries) {
    entries.forEach(entry => {
      if (entry.isIntersecting) {
        const img = entry.target
        img.src = img.dataset.src
        img.classList.remove('lazy')
        this.observer.unobserve(img)
      }
    })
  }
}

// 代码分割
const LazyComponent = React.lazy(() => import('./LazyComponent'))

function App() {
  return (
    <Suspense fallback={<div>Loading...</div>}>
      <LazyComponent />
    </Suspense>
  )
}

// 预加载关键资源
const preloadResource = (href, as) => {
  const link = document.createElement('link')
  link.rel = 'preload'
  link.href = href
  link.as = as
  document.head.appendChild(link)
}

// 预加载关键 CSS
preloadResource('/styles/critical.css', 'style')

2. 缓存策略

// Service Worker 缓存
const CACHE_NAME = 'app-cache-v1'
const urlsToCache = [
  '/',
  '/styles/main.css',
  '/scripts/main.js',
  '/images/logo.png'
]

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 => {
        if (response) {
          return response
        }
        return fetch(event.request)
      })
  )
})

// HTTP 缓存头
app.use(express.static('public', {
  maxAge: '1y',
  etag: true,
  lastModified: true
}))

3. 网络优化

// 请求去重
class RequestDeduplicator {
  constructor() {
    this.pendingRequests = new Map()
  }
  
  async request(url, options = {}) {
    const key = `${url}-${JSON.stringify(options)}`
    
    if (this.pendingRequests.has(key)) {
      return this.pendingRequests.get(key)
    }
    
    const promise = fetch(url, options)
    this.pendingRequests.set(key, promise)
    
    try {
      const result = await promise
      this.pendingRequests.delete(key)
      return result
    } catch (error) {
      this.pendingRequests.delete(key)
      throw error
    }
  }
}

// 请求重试
const retryRequest = async (url, options = {}, maxRetries = 3) => {
  for (let i = 0; i < maxRetries; i++) {
    try {
      const response = await fetch(url, options)
      if (response.ok) {
        return response
      }
    } catch (error) {
      if (i === maxRetries - 1) {
        throw error
      }
      await new Promise(resolve => setTimeout(resolve, 1000 * Math.pow(2, i)))
    }
  }
}

性能分析工具

1. Chrome DevTools

// 性能分析
const startProfiling = () => {
  if (performance.mark) {
    performance.mark('start-profiling')
  }
}

const endProfiling = () => {
  if (performance.mark) {
    performance.mark('end-profiling')
    performance.measure('profiling-duration', 'start-profiling', 'end-profiling')
  }
}

// 内存使用分析
const analyzeMemory = () => {
  if (performance.memory) {
    console.log('内存使用情况:', {
      used: performance.memory.usedJSHeapSize,
      total: performance.memory.totalJSHeapSize,
      limit: performance.memory.jsHeapSizeLimit
    })
  }
}

2. 自动化性能测试

// 使用 Puppeteer 进行性能测试
const puppeteer = require('puppeteer')

async function performanceTest() {
  const browser = await puppeteer.launch()
  const page = await browser.newPage()
  
  // 启用性能监控
  await page.tracing.start({ path: 'trace.json' })
  
  // 访问页面
  await page.goto('https://example.com')
  
  // 等待页面加载完成
  await page.waitForLoadState('networkidle')
  
  // 获取性能指标
  const metrics = await page.evaluate(() => {
    const navigation = performance.getEntriesByType('navigation')[0]
    return {
      loadTime: navigation.loadEventEnd - navigation.loadEventStart,
      domContentLoaded: navigation.domContentLoadedEventEnd - navigation.domContentLoadedEventStart,
      firstPaint: performance.getEntriesByType('paint')[0].startTime
    }
  })
  
  console.log('性能指标:', metrics)
  
  // 停止性能监控
  await page.tracing.stop()
  
  await browser.close()
}

持续优化

1. 性能预算

// 性能预算配置
const performanceBudget = {
  pageLoadTime: 3000,    // 3秒
  firstPaint: 1500,      // 1.5秒
  lcp: 2500,             // 2.5秒
  fid: 100,              // 100ms
  cls: 0.1               // 0.1
}

// 检查性能预算
const checkPerformanceBudget = (metrics) => {
  const violations = []
  
  Object.keys(performanceBudget).forEach(key => {
    if (metrics[key] > performanceBudget[key]) {
      violations.push({
        metric: key,
        actual: metrics[key],
        budget: performanceBudget[key]
      })
    }
  })
  
  if (violations.length > 0) {
    console.warn('性能预算超标:', violations)
    // 发送告警
    sendAlert(violations)
  }
}

2. 自动化优化

// 自动优化图片
const optimizeImages = () => {
  const images = document.querySelectorAll('img')
  images.forEach(img => {
    if (img.dataset.src && !img.src) {
      // 使用 WebP 格式
      const webpSrc = img.dataset.src.replace(/.(jpg|jpeg|png)$/, '.webp')
      img.src = webpSrc
    }
  })
}

// 自动预加载关键资源
const preloadCriticalResources = () => {
  const criticalResources = [
    '/styles/critical.css',
    '/scripts/critical.js',
    '/fonts/main.woff2'
  ]
  
  criticalResources.forEach(resource => {
    const link = document.createElement('link')
    link.rel = 'preload'
    link.href = resource
    link.as = resource.endsWith('.css') ? 'style' : 'script'
    document.head.appendChild(link)
  })
}

总结

Web 性能监控与优化是一个持续的过程,需要:

  1. 建立完善的监控体系:收集关键性能指标
  2. 使用合适的工具:选择合适的监控和分析工具
  3. 实施优化策略:从资源、缓存、网络等方面优化
  4. 持续改进:建立性能预算,持续监控和优化

通过系统性的性能优化,我们可以显著提升用户体验,改善业务指标。记住,性能优化不是一次性的工作,而是需要持续关注和改进的过程。