1483 字
7 分钟
前端性能优化与网络请求

前端性能优化与网络请求#

概述#

前端性能优化是提升用户体验的关键,网络请求优化是其中最重要的一环。通过减少请求数量、压缩资源、合理缓存等手段,可以显著提升页面加载速度。

网络请求分析#

1. 关键性能指标#

  • FP(First Paint):首次绘制时间
  • FCP(First Contentful Paint):首次内容绘制
  • LCP(Largest Contentful Paint):最大内容绘制
  • FID(First Input Delay):首次输入延迟
  • CLS(Cumulative Layout Shift):累计布局偏移

2. 网络瀑布图分析#

DNS 查询    |====|
TCP 连接    |====|
TLS 握手    |====|
请求发送    |==|
等待响应    |=======|
接收数据    |============|

3. Chrome DevTools 网络面板#

  • 请求列表:查看所有网络请求
  • 时间线:分析请求各阶段耗时
  • 瀑布图:可视化请求时序
  • 请求详情:查看请求头、响应头、内容

减少请求数量#

1. 合并资源文件#

// Webpack 配置示例
module.exports = {
  optimization: {
    splitChunks: {
      chunks: 'all',
      cacheGroups: {
        vendors: {
          test: /[\\/]node_modules[\\/]/,
          name: 'vendors',
          chunks: 'all'
        },
        commons: {
          name: 'commons',
          minChunks: 2,
          chunks: 'initial',
          minSize: 0
        }
      }
    }
  }
};

2. 使用 CSS Sprites#

.icon {
  background-image: url('sprites.png');
  background-repeat: no-repeat;
}

.icon-home {
  width: 32px;
  height: 32px;
  background-position: 0 0;
}

.icon-user {
  width: 32px;
  height: 32px;
  background-position: -32px 0;
}

3. 内联关键 CSS#

<!DOCTYPE html>
<html>
<head>
  <style>
    /* 关键CSS内联 */
    .header { display: flex; }
    .logo { width: 100px; }
    /* 非关键CSS异步加载 */
  </style>
  <link rel="preload" href="styles.css" as="style" onload="this.rel='stylesheet'">
  <noscript><link rel="stylesheet" href="styles.css"></noscript>
</head>
</html>

4. 使用 Data URLs#

<!-- 小图片转为 Base64 -->
<img src="data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMjQiIGhlaWdodD0iMjQiIHZpZXdCb3g9IjAgMCAyNCAyNCI+PC9zdmc+">

<!-- CSS 中内联小图片 -->
.icon {
  background-image: url('data:image/svg+xml;utf8,<svg>...</svg>');
}

压缩与优化#

1. 资源压缩#

# Nginx Gzip 配置
gzip on;
gzip_vary on;
gzip_min_length 1024;
gzip_types text/plain text/css text/xml text/javascript 
           application/javascript application/xml+rss 
           application/json image/svg+xml;
gzip_comp_level 6;

2. 图片优化#

// 使用现代图片格式
// WebP:比 JPEG 小 25-35%,支持透明度
// AVIF:比 WebP 更优,但兼容性较差

// 响应式图片
<picture>
  <source srcset="image.avif" type="image/avif">
  <source srcset="image.webp" type="image/webp">
  <img src="image.jpg" alt="描述">
</picture>

// 懒加载
<img src="placeholder.jpg" data-src="real-image.jpg" loading="lazy">

3. 代码压缩#

# 使用工具压缩
# JavaScript: UglifyJS, Terser
# CSS: CSSNano
# HTML: HTMLMinifier

# Webpack 配置
const TerserPlugin = require('terser-webpack-plugin');
const CssMinimizerPlugin = require('css-minimizer-webpack-plugin');

module.exports = {
  optimization: {
    minimize: true,
    minimizer: [
      new TerserPlugin(),
      new CssMinimizerPlugin(),
    ],
  },
};

缓存策略#

1. 浏览器缓存#

# 强缓存
Cache-Control: max-age=31536000, public
Expires: Wed, 13 Mar 2027 14:30:00 GMT

# 协商缓存
ETag: "33a64df551425fcc55e4d42a148795d9f25f89d4"
Last-Modified: Wed, 12 Mar 2026 14:30:00 GMT

2. Service Worker 缓存#

// service-worker.js
const CACHE_NAME = '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); // 网络请求
      })
  );
});

3. CDN 缓存#

<!-- 使用 CDN 加速 -->
<script src="https://cdn.example.com/jquery@3.6.0.min.js"></script>
<link rel="stylesheet" href="https://cdn.example.com/bootstrap@5.1.3/css/bootstrap.min.css">

<!-- 子资源完整性校验 -->
<script 
  src="https://cdn.example.com/jquery@3.6.0.min.js"
  integrity="sha384-...">
</script>

请求优化#

1. 预加载与预连接#

<!-- DNS 预解析 -->
<link rel="dns-prefetch" href="https://api.example.com">

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

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

<!-- 预获取可能需要的资源 -->
<link rel="prefetch" href="next-page.html" as="document">

2. 请求优先级#

// 使用 fetch API 设置优先级
fetch('/api/data', {
  priority: 'high' // high, low, auto
});

// 图片懒加载
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);
});

3. 请求合并与批处理#

// 批量请求示例
class BatchRequest {
  constructor(delay = 100) {
    this.requests = [];
    this.timer = null;
    this.delay = delay;
  }

  add(request) {
    this.requests.push(request);
    this.schedule();
  }

  schedule() {
    if (this.timer) clearTimeout(this.timer);
    this.timer = setTimeout(() => this.execute(), this.delay);
  }

  async execute() {
    if (this.requests.length === 0) return;
    
    const batch = this.requests.splice(0, 10); // 每次最多10个
    const results = await Promise.all(
      batch.map(req => fetch(req.url, req.options))
    );
    
    batch.forEach((req, index) => {
      req.resolve(results[index]);
    });
  }
}

// 使用示例
const batch = new BatchRequest();
batch.add({
  url: '/api/user/1',
  resolve: response => console.log('User 1:', response)
});

监控与测量#

1. Performance API#

// 测量页面性能
const perfData = window.performance.timing;
const loadTime = perfData.loadEventEnd - perfData.navigationStart;
console.log(`页面加载时间: ${loadTime}ms`);

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

// 用户自定义测量
performance.mark('task-start');
// 执行任务...
performance.mark('task-end');
performance.measure('task-duration', 'task-start', 'task-end');

2. 真实用户监控 (RUM)#

// 发送性能数据到分析服务
function sendPerformanceData() {
  const data = {
    url: window.location.href,
    fcp: performance.getEntriesByName('first-contentful-paint')[0]?.startTime,
    lcp: performance.getEntriesByName('largest-contentful-paint')[0]?.startTime,
    fid: performance.getEntriesByName('first-input')[0]?.processingStart,
    cls: performance.getEntriesByName('layout-shift')
      .reduce((sum, entry) => sum + entry.value, 0),
    timestamp: Date.now()
  };

  // 使用 navigator.sendBeacon 异步发送
  navigator.sendBeacon('/api/performance', JSON.stringify(data));
}

// 页面卸载时发送数据
window.addEventListener('beforeunload', sendPerformanceData);

3. 性能预算#

{
  "performanceBudget": {
    "metrics": {
      "fcp": 1000,
      "lcp": 2500,
      "fid": 100,
      "cls": 0.1
    },
    "resourceSizes": {
      "total": 500000,
      "javascript": 200000,
      "css": 50000,
      "images": 200000
    },
    "requests": {
      "total": 15,
      "thirdParty": 5
    }
  }
}

工具与自动化#

1. 构建工具#

// Vite 配置示例
export default {
  build: {
    rollupOptions: {
      output: {
        manualChunks: {
          vendor: ['react', 'react-dom'],
          utils: ['lodash', 'dayjs']
        }
      }
    },
    // 代码分割
    chunkSizeWarningLimit: 1000,
    // 资源内联阈值
    assetsInlineLimit: 4096
  }
};

2. 自动化测试#

// Lighthouse 自动化测试
const lighthouse = require('lighthouse');
const chromeLauncher = require('chrome-launcher');

async function runAudit(url) {
  const chrome = await chromeLauncher.launch();
  const options = {
    logLevel: 'info',
    output: 'json',
    onlyCategories: ['performance'],
    port: chrome.port
  };

  const runnerResult = await lighthouse(url, options);
  const report = runnerResult.report;
  
  await chrome.kill();
  return JSON.parse(report);
}

// WebPageTest 集成
// 使用 webpagetest-api 包进行自动化测试

3. 持续监控#

# GitHub Actions 工作流
name: Performance Monitoring
on:
  schedule:
    - cron: '0 0 * * *'  # 每天运行
  push:
    branches: [main]

jobs:
  performance:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v2
      - name: Run Lighthouse
        uses: foo-software/lighthouse-check-action@master
        with:
          urls: 'https://example.com'
          outputDirectory: './reports'
      - name: Upload Report
        uses: actions/upload-artifact@v2
        with:
          name: lighthouse-report
          path: ./reports

最佳实践总结#

1. 核心原则#

  • 测量优先:没有测量就没有优化
  • 渐进增强:确保基础功能快速可用
  • 按需加载:只加载当前需要的资源
  • 缓存为王:合理利用各级缓存

2. 优化 checklist#

  • 压缩所有文本资源(HTML、CSS、JS)
  • 优化图片格式和尺寸
  • 合并和减少 HTTP 请求
  • 使用 CDN 分发静态资源
  • 实现合理的缓存策略
  • 启用 HTTP/2 或 HTTP/3
  • 使用 Service Worker 缓存
  • 监控真实用户性能数据

3. 持续改进#

  • 定期进行性能审计
  • 设置性能预算并监控
  • A/B 测试优化效果
  • 关注 Core Web Vitals 指标

总结#

前端性能优化是一个系统工程,需要从网络请求、资源加载、代码执行等多个维度进行优化。通过合理的缓存策略、资源压缩、请求优化和持续监控,可以显著提升用户体验和业务指标。


创建时间:2026-03-12 分类:前端网络 标签:性能优化, 网络请求, 前端开发, 性能监控

前端性能优化与网络请求
https://ameng404.com/posts/network/前端性能优化与网络请求/
作者
Ameng
发布于
2026-03-12
许可协议
CC BY-NC-SA 4.0