Skip to content

性能优化的核心维度 ​

一、修正你的笔记(先纠偏,再深化) ​

你的笔记原文问题/建议修正后专业表述
html(设置 http 缓存)略简,且 HTTP 缓存不只在 HTMLHTTP 缓存策略:强缓存(Cache-Control)+ 协商缓存(ETag/Last-Modified),配置在 Nginx/CDN 层,适用于所有静态资源。
推荐选择 css 内联,首屏 css表述正确,可更精准Critical CSS(关键 CSS):将首屏渲染必需的 CSS 内联在 <head> 中,非关键 CSS 异步加载,避免 CSS 阻塞渲染。
减少请求数,更新链接直接返回更新结果而不是重传表述略模糊增量更新(HTTP 缓存 + 文件指纹):资源更新时 URL 的 hash 变化(如 main.a1b2c3.js),浏览器识别为新资源重新请求,未变化的资源复用缓存,无需重传。
test section observation❌ 难以理解Lighthouse / Performance 监控:用 Lighthouse 检测 Core Web Vitals(LCP、FID、CLS),持续观测性能指标。
75 秒后优化❌ 语义不清空闲时优化(requestIdleCallback):在浏览器空闲时段执行低优先级任务(如上报日志、预加载下一屏数据),避免阻塞主线程。
缓存时间 5/scroll(resize),缓存时间 10 秒后使用❌ 表述混乱防抖(Debounce)与节流(Throttle):scroll/resize 事件用节流(如 100ms 触发一次),搜索框输入用防抖(如 300ms 后触发)。
使用ITE(基于Buid 部分建名赖)❌ 应该是 ViteVite:基于 ES Module 的开发服务器,按需编译、热更新只更新修改的模块,生产环境用 Rollup 打包,体积更小。
并环境 Rollup打包,体积更小✅ Vite 生产环境用 RollupVite 生产构建:使用 Rollup 打包,支持 Tree Shaking、代码分割、更优的产物体积。

二、四层优化体系(面试时按这个结构讲) ​

面试官问“前端性能优化你做过哪些?”——你按 “网络层 → 渲染层 → 运行时 → 工程化” 四个维度来答,条理清晰,覆盖全面:

┌─────────────────────────────────────────────────────────────┐
│                    前端性能优化四层体系                       │
├─────────────────────────────────────────────────────────────┤
│ 1. 网络层(加载更快)                                        │
│    - HTTP 缓存(强缓存 + 协商缓存)                          │
│    - 资源压缩(Gzip/Brotli)                                │
│    - 图片优化(WebP/AVIF、懒加载、响应式图片)               │
│    - 减少请求数(雪碧图、字体图标、请求合并)                 │
│    - CDN 加速 + HTTP/2 多路复用                             │
├─────────────────────────────────────────────────────────────┤
│ 2. 渲染层(渲染更快)                                        │
│    - Critical CSS(首屏关键 CSS 内联)                      │
│    - 异步加载非关键 CSS/JS(defer/async)                   │
│    - 路由懒加载 + 组件懒加载                                 │
│    - 字体加载优化(font-display)                           │
├─────────────────────────────────────────────────────────────┤
│ 3. 运行时(交互更流畅)                                      │
│    - 防抖/节流(高频事件控制)                               │
│    - 虚拟滚动(长列表优化)                                  │
│    - requestAnimationFrame(动画优化)                      │
│    - requestIdleCallback(空闲任务调度)                    │
│    - React/Vue 框架级优化(memo、useMemo、不可变数据)       │
├─────────────────────────────────────────────────────────────┤
│ 4. 工程化(构建更高效)                                      │
│    - Vite(ESM 按需编译、HMR)                              │
│    - Webpack 优化(多进程打包、代码分割、Tree Shaking)      │
│    - 组件库按需加载(babel-plugin-import)                  │
└─────────────────────────────────────────────────────────────┘

三、每个维度的详细解答(代码 + 场景) ​

第一层:网络层优化 ​

1. HTTP 缓存策略 ​

面试话术:

“缓存是性能优化的第一优先级。我通常配置 强缓存 + 协商缓存 双层策略:静态资源(JS/CSS/图片)设置 Cache-Control: max-age=31536000(一年),配合文件指纹(main.a1b2c3.js)实现精准的缓存更新。HTML 文件设置 Cache-Control: no-cache,确保每次请求验证最新版本。”

Nginx 配置示例:

nginx
# 静态资源(带指纹)—— 强缓存一年
location ~* \.(js|css|png|jpg|jpeg|gif|svg|woff|woff2)$ {
    expires 1y;
    add_header Cache-Control "public, immutable";
}

# HTML 文件 —— 协商缓存
location ~* \.html$ {
    add_header Cache-Control "no-cache, must-revalidate";
}

2. 资源压缩 ​

“所有静态资源传输前开启 Gzip 或 Brotli 压缩,压缩率可达 70% 以上。图片使用 WebP/AVIF 格式替代传统 PNG/JPG,配合 <picture> 标签做降级。”

html
<!-- 响应式图片 + WebP 降级 -->
<picture>
  <source srcset="image.avif" type="image/avif">
  <source srcset="image.webp" type="image/webp">
  <img src="image.jpg" alt="描述" loading="lazy">
</picture>

3. 减少请求数 ​

“小图标用 SVG Sprite 或 字体图标 合并请求,多个 API 请求用 BFF 层聚合,或使用 HTTP/2 多路复用 让并发请求不再受限于浏览器同域名 6 个连接的限制。”

4. 结合你的项目 ​

(IRMP 报告生成平台):“IRMP 的 PDF 报告预览中,我将模板引擎的渲染结果缓存到 CDN,用户重复查看同一报告时直接走缓存,二次打开速度从 3s 降到 200ms。”

第二层:渲染层优化 ​

1. Critical CSS(关键 CSS) ​

“首屏渲染被 CSS 阻塞是常见的性能瓶颈。我使用 Critical(或 critical 插件) 提取首屏关键 CSS 内联到 <head>,非关键 CSS 异步加载,LCP(最大内容绘制)平均提升 30%。”

html
<head>
  <!-- 首屏关键 CSS 内联 -->
  <style>.header{...}.hero{...}</style>
  <!-- 非关键 CSS 异步加载 -->
  <link rel="preload" href="non-critical.css" as="style" onload="this.onload=null;this.rel='stylesheet'">
  <noscript><link rel="stylesheet" href="non-critical.css"></noscript>
</head>

2. 路由懒加载 + 组件懒加载 ​

(结合你的 IAMP 项目):“IAMP 的 Three.js 点云模块只在隧道检测页面使用,我使用 路由懒加载(() => import('./views/PointCloud.vue')),用户访问该页面时才加载 Three.js 库,首屏 JS 体积从 2.3MB 降到 500KB。”

React 写法:

javascript
const PointCloud = lazy(() => import('./pages/PointCloud'));
// 配合 Suspense
<Suspense fallback={<Loader />}>
  <PointCloud />
</Suspense>

Vue 写法:

javascript
// 你笔记里提到的 defineAsyncComponent
const PointCloud = defineAsyncComponent(() => 
  import('./components/PointCloud.vue')
);

3. 字体优化 ​

“字体文件通常较大,我用 font-display: swap 让文字先以系统字体渲染,Web 字体加载完成后替换,消除‘无文字闪烁(FOIT)’。”

css
@font-face {
  font-family: 'CustomFont';
  src: url('/fonts/custom.woff2') format('woff2');
  font-display: swap; /* 关键!先展示系统字体 */
}

第三层:运行时优化 ​

1. 防抖(Debounce)与节流(Throttle) ​

(结合你的 MMMP 大屏):“MMMP 大屏的图表窗口 resize 事件,我用节流控制每秒最多重绘 1 次;搜索框输入我用防抖,用户停止输入 300ms 后才发起请求,API 调用量减少了 80%。”

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

// 防抖(搜索输入)
function debounce(fn, delay) {
  let timer = null;
  return (...args) => {
    clearTimeout(timer);
    timer = setTimeout(() => fn(...args), delay);
  };
}

2. 虚拟滚动(长列表优化) ​

(结合你的 WeLink 消息列表):“WeLink 的 IM 消息列表采用 虚拟滚动(react-window),只渲染视口可见的 10-15 条消息,支持 10000+ 条消息 60fps 流畅滚动。图片消息异步加载后通过 resetAfterIndex 动态更新高度。”

3. requestAnimationFrame 与 requestIdleCallback ​

requestAnimationFrame:用于动画和 DOM 批量更新,由浏览器在下一次重绘前执行,保证 60fps 流畅度。

requestIdleCallback:用于低优先级任务(如日志上报、数据预加载),在浏览器空闲时段执行,不阻塞用户交互。

javascript
// 配合 React 的 useLayoutEffect 或 Vue 的 nextTick 使用
// 1. 批量 DOM 更新用 requestAnimationFrame
function batchUpdate(updates) {
  requestAnimationFrame(() => {
    updates.forEach(fn => fn());
  });
}

// 2. 空闲时预加载下一屏数据
requestIdleCallback(() => {
  preloadNextPage();
}, { timeout: 2000 });

4. React 性能优化(你笔记里的要点展开) ​

“我在 WeLink 项目中,采用 三层优化策略:

  1. 减少渲染次数:React.memo 包裹纯展示组件,配合 useCallback/useMemo 稳定函数和数据的引用。
  2. 减少渲染耗时:拆分子组件,配合 useTransition 将低优先级更新标记为‘过渡任务’,让高优先级交互(如输入)优先响应。
  3. 减少内存占用:大列表用虚拟滚动,图片懒加载,组件卸载时清理定时器和事件监听。”
javascript
// 组合使用 memo + useCallback + useMemo
const Child = React.memo(({ data, onAction }) => {
  return <div onClick={onAction}>{data.name}</div>;
});

function Parent({ items }) {
  const handleAction = useCallback(() => { /* ... */ }, []);
  const sortedData = useMemo(() => items.sort((a,b) => a.id - b.id), [items]);
  return <Child data={sortedData} onAction={handleAction} />;
}

5. Vue 性能优化 ​

(结合你的 IRMP 项目):“在 IRMP 平台,我使用了:

  • 组件懒加载:defineAsyncComponent 实现大体积组件按需加载。
  • v-once 指令:对静态内容(如报告模板的固定标题)使用 v-once,只渲染一次,减少更新开销。
  • computed 缓存:复杂计算用 computed 缓存结果,避免每次渲染重新计算。”
vue
<template>
  <!-- 静态内容只渲染一次 -->
  <header v-once>{{ fixedTitle }}</header>
  <!-- 动态列表用 computed 缓存 -->
  <div v-for="item in filteredList" :key="item.id">{{ item.name }}</div>
</template>

<script setup>
import { defineAsyncComponent, computed } from 'vue';

// 组件懒加载
const HeavyComponent = defineAsyncComponent(() => 
  import('./HeavyComponent.vue')
);

// computed 缓存计算结果
const filteredList = computed(() => 
  rawList.value.filter(item => item.visible)
);
</script>

第四层:工程化优化 ​

1. Vite 优化(你笔记里提到的) ​

“我在 IRMP 项目从 Vue CLI(Webpack)迁移到 Vite 后,开发服务器启动时间从 45s 降到 2s,HMR 更新从 3s 降到 100ms。核心原因是 Vite 基于 ES Module,只编译当前访问的模块,不打包整个应用。

生产环境 Vite 使用 Rollup 打包,代码分割更智能(基于动态导入自动拆分),配合 Tree Shaking 剔除未使用代码,最终产物体积比 Webpack 构建小约 30%。”

2. Webpack 优化 ​

“在维护传统 Webpack 项目时,我通过 多进程打包(thread-loader)、缓存(cache-loader)、代码分割(splitChunks) 将构建时间从 120s 压缩到 35s。”

javascript
// webpack.config.js
module.exports = {
  // 1. 多进程打包
  module: {
    rules: [
      {
        test: /\.js$/,
        use: ['thread-loader', 'babel-loader'],
      },
    ],
  },
  // 2. 代码分割
  optimization: {
    splitChunks: {
      chunks: 'all',
      cacheGroups: {
        vendor: {
          test: /[\\/]node_modules[\\/]/,
          name: 'vendors',
          chunks: 'all',
        },
      },
    },
  },
};

3. 组件库按需加载 ​

“使用 Element Plus / Ant Design 时,配置 babel-plugin-import 实现按需加载,只引入使用到的组件。在 IRMP 项目中,Element Plus 的构建体积从全量 800KB 降到按需加载 180KB。”

javascript
// babel.config.js
module.exports = {
  plugins: [
    ['import', {
      libraryName: 'element-plus',
      customStyleName: (name) => `element-plus/theme-chalk/${name}.css`,
    }],
  ],
};

四、面试完整话术(“性能优化”一块,直接背这个) ​

“面试官,我把前端性能优化总结为 ‘四层体系’,在每个环节都有相应的优化手段:

第一,网络层——让资源加载更快。配置 HTTP 强缓存(带文件指纹)+ 协商缓存,开启 Gzip/Brotli 压缩,图片使用 WebP/AVIF 格式,通过 CDN 加速静态资源,借助 HTTP/2 多路复用 突破并发限制。

第二,渲染层——让页面显示更快。首屏关键 CSS 内联(Critical CSS),非关键 JS 用 defer/async 延迟加载,路由和组件使用 懒加载(React 的 lazy + Suspense,Vue 的 defineAsyncComponent)。在 WeLink 和 IRMP 中,我通过路由懒加载将首屏 JS 体积减少了 60% 以上。

第三,运行时——让交互更流畅。高频事件用 防抖/节流 控制执行频率;长列表用 虚拟滚动 支撑万级数据 60fps 滚动;动画用 requestAnimationFrame 调度;低优先级任务(如日志上报)用 requestIdleCallback 在空闲时执行,不阻塞用户操作。

第四,工程化——让构建更高效。开发环境用 Vite 享受极快的冷启动和 HMR;生产环境利用 代码分割 + Tree Shaking 精简产物;组件库按需加载;通过多进程打包和缓存压缩构建时间。

我始终坚持 ‘性能是设计出来的,不是优化出来的’ ——在项目初期就建立性能基线(Lighthouse 评分、首屏加载时间、FCP/LCP 指标),每次迭代监控变化,确保性能不退化。”

五、最后的“认知升华”(让面试官觉得你懂性能本质) ​

“我理解性能优化的本质是 ‘资源的管理与调度’ ——网络层面管理资源传输(缓存、压缩、CDN),渲染层面管理资源加载顺序(关键路径、懒加载),运行时管理计算资源(防抖节流、虚拟滚动、帧率控制)。前端工程师的价值在于在这三个维度上找到最优平衡点,而不是单纯堆砌优化手段。”

最近更新