编程进阶网 编程进阶网
首页
  • 在线工具
  • JSON工具
  • 文本工具
  • 图片处理
  • 文档转化
  • 代码压缩
  • 加解密
  • 时间日期
  • 网络工具
  • 颜色设计
  • 二维码
  • 开发实用
  • 计算机原理
  • 操作系统
  • 网络协议
  • 数据库原理
  • 面向对象
  • 设计原则
  • 设计模式
  • 系统架构
  • 性能优化
  • 编程原理
  • 方案设计
  • 稳定可靠
  • 工程运维
  • 基础认知
  • 线性结构
  • 树与哈希
  • 工业级实现
  • 算法思想
  • 实战与综合
  • 算法题考核
  • C语言入门
  • C综合案例
  • C专栏博客
  • C标准集库
  • C++入门教程
  • C++综合案例
  • C++专栏博客
  • C++编程技巧
  • Java入门教程
  • Java综合案例
  • Java专栏博客
  • Go入门教程
  • Go综合案例
  • Go专栏博客
  • Go开发技巧
  • JavaScript入门
  • JavaScript高级
  • Android库解读
  • Android专栏
  • iOS ObjC入门
  • iOS Swift入门
  • iOS入门精通
  • Web之Html手册
  • Web之TypeScript
  • Web之Vue高级进阶
  • Linux之QML入门
  • Linux之QT核心库
  • Python教程
  • Shell&Bash教程
  • 工具脚本
  • 自动化脚本
  • 质量保障
  • 产品思考
  • 软实力
  • 开发流程
  • Git应用
  • 技术模版
  • 技术规范
  • Markdown
  • Mermaid
  • 开源协议
  • 关于我
  • 自我精进
  • 职场管理
  • 职场面试
  • 心情杂货
  • 友情链接

杨充

专注编程 · 终身学习者
首页
  • 在线工具
  • JSON工具
  • 文本工具
  • 图片处理
  • 文档转化
  • 代码压缩
  • 加解密
  • 时间日期
  • 网络工具
  • 颜色设计
  • 二维码
  • 开发实用
  • 计算机原理
  • 操作系统
  • 网络协议
  • 数据库原理
  • 面向对象
  • 设计原则
  • 设计模式
  • 系统架构
  • 性能优化
  • 编程原理
  • 方案设计
  • 稳定可靠
  • 工程运维
  • 基础认知
  • 线性结构
  • 树与哈希
  • 工业级实现
  • 算法思想
  • 实战与综合
  • 算法题考核
  • C语言入门
  • C综合案例
  • C专栏博客
  • C标准集库
  • C++入门教程
  • C++综合案例
  • C++专栏博客
  • C++编程技巧
  • Java入门教程
  • Java综合案例
  • Java专栏博客
  • Go入门教程
  • Go综合案例
  • Go专栏博客
  • Go开发技巧
  • JavaScript入门
  • JavaScript高级
  • Android库解读
  • Android专栏
  • iOS ObjC入门
  • iOS Swift入门
  • iOS入门精通
  • Web之Html手册
  • Web之TypeScript
  • Web之Vue高级进阶
  • Linux之QML入门
  • Linux之QT核心库
  • Python教程
  • Shell&Bash教程
  • 工具脚本
  • 自动化脚本
  • 质量保障
  • 产品思考
  • 软实力
  • 开发流程
  • Git应用
  • 技术模版
  • 技术规范
  • Markdown
  • Mermaid
  • 开源协议
  • 关于我
  • 自我精进
  • 职场管理
  • 职场面试
  • 心情杂货
  • 友情链接
  • README
  • Android提升进阶

  • iOS开发和进阶

  • Web开发和进阶

    • README
    • HTML工具手册

    • CSS样式与布局

    • JavaScript核心

    • TypeScript入门

    • Vue高级进阶

    • Web工程化实践

      • 前端工程化概述
      • Webpack构建实战
      • Vite构建实战
      • 代码规范与质量
      • 前端性能优化
        • 1. 案例引入:用户的 3 秒忍耐极限
        • 2. Core Web Vitals——Google 的性能三指标
          • 2.1 LCP(最大内容绘制)← "主要内容可见速度"
          • 2.2 FID / INP(交互延迟)← "页面响应速度"
          • 2.3 CLS(累计布局偏移)← "页面跳动幅度"
        • 3. 资源加载优化
          • 3.1 关键渲染路径优化
          • 3.2 资源提示(Resource Hints)
          • 3.3 图片优化
          • 3.4 字体优化
        • 4. 渲染性能
          • 4.1 理解浏览器渲染流水线
          • 4.2 减少重排和重绘
          • 4.3 CSS containment
        • 5. Bundle 分析与优化
          • 5.1 分析打包体积
          • 5.2 常见体积杀手
          • 5.3 按需引入
        • 6. 缓存策略
        • 7. 性能监控
          • 7.1 测量 Core Web Vitals
          • 7.2 性能预算
        • 8. 速查表
  • Linux应用开发

  • IoT智能硬件开发

  • Apps
  • Web开发和进阶
  • Web工程化实践
杨充
2026-06-23
目录

前端性能优化

# 05.前端性能优化

Core Web Vitals、资源加载优化、渲染性能、Bundle 分析——掌握"网页快不快"的测量与优化方法。

# 1. 案例引入:用户的 3 秒忍耐极限

某电商首页的真实 Lighthouse 报告:

  FCP (First Contentful Paint)    → 3.1 秒  🔴 差
  LCP (Largest Contentful Paint)  → 5.8 秒  🔴 差
  TBT (Total Blocking Time)       → 890 ms  🔴 差
  CLS (Cumulative Layout Shift)   → 0.32    🔴 差

结果:跳出率 58%,转化率比同行业低 40%

优化后:
  FCP  → 0.8 秒  🟢 好    (减少图片阻塞 + 延迟非关键 JS)
  LCP  → 1.6 秒  🟢 好    (大图懒加载 + CDN)
  TBT  → 120 ms  🟢 好    (JS 代码分割 + Worker)
  CLS  → 0.01    🟢 好    (图片/广告预设尺寸)

# 2. Core Web Vitals——Google 的性能三指标

# 2.1 LCP(最大内容绘制)← "主要内容可见速度"

LCP 测量的是:视口中最大元素(图片/文本块)加载完成的时间

目标:< 2.5 秒 → 好
      2.5~4.0 秒 → 需要改进
      > 4.0 秒 → 差

优化方向:
  1. 减少服务器响应时间(CDN/TTFB)
  2. 优先加载首屏关键资源(preload 关键 CSS/图片)
  3. 延迟加载非首屏元素(lazy loading)

# 2.2 FID / INP(交互延迟)← "页面响应速度"

FID:用户首次交互(点击/输入)到浏览器响应的时间(即将被 INP 取代)
INP:页面生命周期内最长/最卡的那次交互延迟

目标:< 100 ms → 好
      < 200 ms → 需要改进
      > 500 ms → 差

优化方向:
  1. 拆分长任务(long task > 50ms)
  2. 代码分割(首屏只加载必要的 JS)
  3. Web Worker 处理密集计算(不阻塞主线程)

# 2.3 CLS(累计布局偏移)← "页面跳动幅度"

CLS 测量的是:页面加载过程中,元素突然"跳"到新位置的累积偏移

常见原因:
  1. 图片没有预设尺寸 → 加载后撑开布局
  2. 动态插入广告 → 已有内容被推开
  3. Web 字体加载 → 文本大小改变

目标:< 0.1 → 好
      0.1~0.25 → 需要改进
      > 0.25 → 差

优化方向:
  1. 所有 <img> / <video> 必须设置 width/height
  2. 动态内容预留空间(如广告占位 div)
  3. 使用 font-display: swap(减少字体闪烁)

# 3. 资源加载优化

# 3.1 关键渲染路径优化

浏览器渲染一个页面的完整链路:

HTML 解析
  ↓ 遇到 <link rel="stylesheet">
CSS 下载 + 解析(阻塞渲染!)
  ↓ 遇到 <script>
JS 下载 + 执行(阻塞解析!HTML 解析暂停)
  ↓ HTML 继续解析
DOM Tree + CSSOM Tree → Render Tree → Layout → Paint

优化策略:
  1. CSS:关键 CSS 内联在 <head> 中(消除外部请求)
  2. JS:非关键脚本 defer(延迟执行)或 async(异步下载)
  3. 资源提示:<link rel="preload"> 提前加载关键资源

# 3.2 资源提示(Resource Hints)

<head>
    <!-- preload:告诉浏览器"这个资源 ASAP 加载"(用于当前页面关键资源) -->
    <link rel="preload" href="/fonts/Main.woff2" as="font" crossorigin>
    <link rel="preload" href="/hero-image.webp" as="image">

    <!-- prefetch:告诉浏览器"这个资源可能下个页面用"(低优先级) -->
    <link rel="prefetch" href="/page2.js">

    <!-- preconnect:提前建立连接(DNS + TCP + TLS) -->
    <link rel="preconnect" href="https://api.example.com">

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

    <!-- 脚本加载策略 -->
    <script src="/app.js" defer></script>   <!-- HTML 解析完后执行,保持顺序 -->
    <script src="/analytics.js" async></script> <!-- 下载完立刻执行,不保证顺序 -->
</head>

# 3.3 图片优化

图片是前端最大的字节消耗(平均占页面 45%~60%)

策略:
  1. 选格式:照片用 WebP/AVIF(比 JPEG 小 25~35%),图标用 SVG
  2. 设尺寸:<img width="800" height="600"> 防止 CLS
  3. 响应式:<img srcset="small.webp 400w, large.webp 800w" sizes="(max-width:600px) 400px, 800px">
  4. 懒加载:<img loading="lazy"> 原生支持
  5. CDN + 压缩:通过 CDN 的图片处理服务在线转换格式和尺寸

# 3.4 字体优化

@font-face {
    font-family: 'CustomFont';
    src: url('/fonts/CustomFont.woff2') format('woff2');
    font-display: swap;        /* 马上用系统字体,加载完后替换 */
    /* 替代:
       font-display: optional  极短等待(~100ms)后不替换
                       auto     浏览器默认
                       block    一直白屏等字体(不推荐) */
}

# 4. 渲染性能

# 4.1 理解浏览器渲染流水线

HTML
  ↓ 解析
DOM Tree
  ↓   + CSSOM Tree  ← 这个阶段被 CSS 阻塞
Render Tree   (结合 DOM + 样式,隐藏节点不在树上)
  ↓
Layout        (计算每个元素的位置和尺寸)
  ↓
Paint         (绘制像素到图层)
  ↓
Composite     (把各图层合成到屏幕)

性能瓶颈在这三个阶段:
  Layout  → 重排(reflow):修改几何属性触发
  Paint   → 重绘(repaint):仅修改外观触发
  Composite → 合成:最便宜,不触发 Layout/Paint

# 4.2 减少重排和重绘

/* 触发重排的操作(尽量避免在动画中使用) */
element.offsetWidth;     /* 读取几何属性——强制同步 Layout */
element.style.width;     /* 修改几何属性 */
element.classList.add;   /* 修改可能改变布局的 class */

/* 只触发重绘(比重排好,但仍消耗) */
element.style.color
element.style.background

/* 只触发合成(性能最佳) */
element.style.transform  /* translate / scale / rotate */
element.style.opacity

/* 批量 DOM 修改 */
// ❌ 每次循环都触发 Layout
for (let i = 0; i < 100; i++) {
    element.style.width = i + 'px';
}

// ✅ 用 requestAnimationFrame 合并
requestAnimationFrame(() => {
    for (let i = 0; i < 100; i++) {
        element.style.width = i + 'px';
    }
});

# 4.3 CSS containment

.widget {
    contain: layout style paint;
    /* 告诉浏览器:这个元素的内部变化不会影响外部 */
    /* 浏览器可以跳过全局 Layout,只在内部重新计算——大幅提升性能 */
}

/* 值的组合:
   content-visibility: auto  = 视口外的元素自动跳过渲染(推荐) */
.lazy-section {
    content-visibility: auto;
    contain-intrinsic-size: 0 500px;  /* 占位高度,防滚动条跳动 */
}

# 5. Bundle 分析与优化

# 5.1 分析打包体积

# Vite 的打包分析
npm run build
# 自动生成 dist/stats.html → 浏览器打开查看各模块大小

# Webpack 的打包分析
npx webpack --profile --json > stats.json
# 上传到 https://webpack.github.io/analyse/

# 或用 rollup-plugin-visualizer(兼容 Webpack/Vite)

# 5.2 常见体积杀手

常见大体积来源和解决方案:

1. moment.js (232KB)  → dayjs (2KB):API 几乎兼容
2. lodash 全量 (72KB)  → lodash-es (按需引入) 或直接用原生 API
3. Element Plus 全量 → unplugin-vue-components 按需引入
4. 未压缩的图片 → 切换到 WebP/AVIF + CDN 转换
5. node_modules 重复打包 → splitChunks 提取 vendor

# 5.3 按需引入

// ❌ 全量引入
import moment from 'moment';

// ✅ 按需引入 + Tree Shaking
import dayjs from 'dayjs';  // 2KB

// ❌
import { debounce } from 'lodash';

// ✅
import debounce from 'lodash-es/debounce';  // 只引入一个函数 ~1KB

// 或者用原生实现
const debounce = (fn, delay) => {
    let timer;
    return (...args) => {
        clearTimeout(timer);
        timer = setTimeout(() => fn(...args), delay);
    };
};

# 6. 缓存策略

文件类型              缓存策略                     原因
─────────────────────────────────────────────────────────
index.html            no-cache (每次验证)           入口文件必须是最新
app.[hash].js         max-age=31536000, immutable   有 hash,永久缓存
vendor.[hash].js      max-age=31536000, immutable   第三方库很少变
[hash].css            max-age=31536000, immutable   同 JS
logo.[hash].png       max-age=31536000, immutable   有 hash
fonts/                max-age=31536000              字体变化少

Nginx 配置:
location /assets/ {
    expires 1y;
    add_header Cache-Control "public, immutable";
}
location / {
    add_header Cache-Control "no-cache";  # 每次验证
}

# 7. 性能监控

# 7.1 测量 Core Web Vitals

// 使用 web-vitals 库
import { onCLS, onINP, onLCP } from 'web-vitals';

function sendToAnalytics({ name, value, id }) {
    // 发送到自建埋点或 Google Analytics
    navigator.sendBeacon('/api/vitals', JSON.stringify({ name, value, id }));
}

onCLS(sendToAnalytics);
onINP(sendToAnalytics);
onLCP(sendToAnalytics);

# 7.2 性能预算

设定性能目标,CI 中自动检测:

  Total JS bundle  < 200KB (gzip)
  Total CSS bundle < 50KB  (gzip)
  LCP              < 2.5s
  TBT              < 200ms

使用 bundlesize 或 lighthouse-ci 在 PR 中自动报告

# 8. 速查表

问题 检查方法 优化方向
首屏慢 Lighthouse LCP preload 关键资源、延迟非关键 JS
交互卡 Lighthouse TBT / INP 拆分长任务、代码分割
布局跳动 手动测试 / CLS 预设图片尺寸、预留动态内容空间
包体积大 rollup-plugin-visualizer 按需引入、Tree Shaking、chunk 拆分
图片太大 Lighthouse 图片审计 WebP/AVIF、srcset、CDN
字体阻塞 网络面板 font-display:swap、preload 字体
缓存失效 响应头 contenthash + immutable
重排频繁 Performance 面板 批量 DOM、requestAnimationFrame

性能优化三问(每个优化决策前):

  1. 问题真的是瓶颈吗?(先用 Lighthouse 测量)
  2. 优化后对用户体验改善多少?(设定可量化的目标)
  3. 优化的代价是什么?(开发成本 vs 性能收益)

专栏完结。回顾 5 篇:01.前端工程化概述 → 02.Webpack构建实战 → 03.Vite构建实战 → 04.代码规范与质量 → 05.前端性能优化

上次更新: 2026/06/24, 14:17:21
代码规范与质量
Linux应用开发

← 代码规范与质量 Linux应用开发→

最近更新
01
CSS选择器入门
06-23
02
CSS定位与层级
06-23
03
CSS盒模型详解
06-23
更多文章>
Theme by Vdoing | Copyright © 2019-2026 杨充 | MIT License | 鄂ICP备2024073355号-1 | 鄂ICP备2024073355号
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式