Skip to content

性能优化

性能指标

核心Web指标

  • FCP (First Contentful Paint): 首次内容绘制
  • LCP (Largest Contentful Paint): 最大内容绘制
  • FID (First Input Delay): 首次输入延迟
  • CLS (Cumulative Layout Shift): 累积布局偏移
  • TTI (Time to Interactive): 可交互时间
  • TTFB (Time to First Byte): 首字节时间

性能测量

javascript
// Performance API
const perfData = performance.getEntriesByType('navigation')[0];

console.log('页面加载时间:', perfData.loadEventEnd - perfData.fetchStart);
console.log('DOM解析时间:', perfData.domContentLoadedEventEnd - perfData.domContentLoadedEventStart);
console.log('首次内容绘制:', perfData.responseStart - perfData.fetchStart);

加载性能优化

1. 减少HTTP请求

html
<!-- 不好的做法 -->
<link rel="stylesheet" href="style1.css">
<link rel="stylesheet" href="style2.css">
<link rel="stylesheet" href="style3.css">

<!-- 好的做法 -->
<link rel="stylesheet" href="styles.css">

2. 使用CDN

html
<!-- 使用CDN加载资源 -->
<script src="https://cdn.example.com/jquery.min.js"></script>
<link rel="stylesheet" href="https://cdn.example.com/bootstrap.min.css">

3. 启用压缩

http
Content-Encoding: gzip
Content-Encoding: br

4. 使用缓存

http
Cache-Control: max-age=3600
ETag: "33a64df551425fcc55e4d42a148795d9f25f89d4"

5. 延迟加载

html
<!-- 延迟加载JavaScript -->
<script src="script.js" defer></script>
<script src="script.js" async></script>

<!-- 懒加载图片 -->
<img src="image.jpg" loading="lazy">

6. 预加载

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

7. 内联关键CSS

html
<!DOCTYPE html>
<html>
<head>
  <style>
    .header {
      background-color: #333;
      color: white;
      padding: 20px;
    }
  </style>
  
  <link rel="preload" href="main.css" as="style" onload="this.onload=null;this.rel='stylesheet'">
  <noscript><link rel="stylesheet" href="main.css"></noscript>
</head>
<body>
  <header class="header">
    <h1>标题</h1>
  </header>
</body>
</html>

渲染性能优化

1. 减少DOM操作

javascript
// 不好的做法:频繁操作DOM
for (let i = 0; i < 100; i++) {
  document.body.appendChild(document.createElement('div'));
}

// 好的做法:使用DocumentFragment
const fragment = document.createDocumentFragment();
for (let i = 0; i < 100; i++) {
  fragment.appendChild(document.createElement('div'));
}
document.body.appendChild(fragment);

2. 避免重排和重绘

javascript
// 不好的做法:频繁读取和写入布局信息
for (let i = 0; i < 100; i++) {
  element.style.width = element.offsetWidth + 1 + 'px';
}

// 好的做法:批量读取和写入
const width = element.offsetWidth;
for (let i = 0; i < 100; i++) {
  element.style.width = width + i + 'px';
}

3. 使用transform和opacity

javascript
// 不好的做法:使用left/top
element.style.left = '10px';
element.style.top = '10px';

// 好的做法:使用transform
element.style.transform = 'translateX(10px) translateY(10px)';

4. 使用will-change

javascript
element.style.willChange = 'transform, opacity';

5. 使用硬件加速

javascript
element.style.transform = 'translateZ(0)';
element.style.transform = 'translate3d(0, 0, 0)';

资源优化

1. 图片优化

html
<!-- 使用合适的格式 -->
<picture>
  <source srcset="image.webp" type="image/webp">
  <img src="image.jpg" alt="图片">
</picture>

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

<!-- 懒加载图片 -->
<img src="image.jpg" loading="lazy">

2. 字体优化

css
/* 使用系统字体 */
body {
  font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
}

/* 使用font-display */
@font-face {
  font-family: 'MyFont';
  src: url('myfont.woff2') format('woff2');
  font-display: swap;
}

3. JavaScript优化

javascript
// 延迟加载非关键JavaScript
<script src="critical.js"></script>
<script src="non-critical.js" defer></script>

// 使用async加载独立JavaScript
<script src="analytics.js" async></script>

// 代码分割
import('./module.js').then(module => {
  module.doSomething();
});

4. CSS优化

css
/* 移除未使用的CSS */
.button {
  padding: 10px 20px;
  background-color: #007bff;
  color: white;
  border: none;
  border-radius: 4px;
  cursor: pointer;
}

/* 使用简写属性 */
.button {
  padding: 10px 20px;
  margin: 10px 20px;
}

网络优化

1. 使用HTTP/2

http
HTTP/2支持多路复用、头部压缩、服务器推送等特性

2. 使用HTTP/3

http
HTTP/3基于QUIC协议,提供更快的连接建立和更好的性能

3. 使用Service Worker

javascript
// 注册Service Worker
if ('serviceWorker' in navigator) {
  navigator.serviceWorker.register('/sw.js')
    .then(registration => {
      console.log('Service Worker注册成功');
    });
}

4. 使用WebSocket

javascript
// 使用WebSocket进行实时通信
const socket = new WebSocket('ws://localhost:8080');
socket.onmessage = function(event) {
  console.log('收到消息:', event.data);
};

代码优化

1. 减少代码体积

javascript
// 使用Tree Shaking
import { foo } from './module.js';

// 使用代码压缩
// webpack、Rollup等工具会自动压缩代码

2. 使用事件委托

javascript
// 不好的做法:为每个元素添加事件监听器
const items = document.querySelectorAll('.item');
items.forEach(item => {
  item.addEventListener('click', function() {
    console.log('点击了项目');
  });
});

// 好的做法:使用事件委托
document.addEventListener('click', function(event) {
  if (event.target.classList.contains('item')) {
    console.log('点击了项目');
  }
});

3. 使用防抖和节流

javascript
// 防抖
function debounce(func, delay) {
  let timeout;
  return function() {
    clearTimeout(timeout);
    timeout = setTimeout(() => func.apply(this, arguments), delay);
  };
}

// 节流
function throttle(func, delay) {
  let lastCall = 0;
  return function() {
    const now = Date.now();
    if (now - lastCall >= delay) {
      func.apply(this, arguments);
      lastCall = now;
    }
  };
}

// 使用防抖
window.addEventListener('resize', debounce(function() {
  console.log('窗口大小改变');
}, 300));

// 使用节流
window.addEventListener('scroll', throttle(function() {
  console.log('滚动事件');
}, 100));

监控和分析

1. 使用Performance API

javascript
// 测量代码执行时间
const start = performance.now();

for (let i = 0; i < 1000000; i++) {
}

const end = performance.now();
console.log('执行时间:', end - start);

2. 使用Lighthouse

bash
# 安装Lighthouse
npm install -g lighthouse

# 运行Lighthouse
lighthouse https://example.com

3. 使用Web Vitals

javascript
// 安装web-vitals
npm install web-vitals

// 使用web-vitals
import { getCLS, getFID, getLCP } from 'web-vitals';

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

面试常见问题

1. 如何优化页面加载性能?

  • 减少HTTP请求
  • 使用CDN
  • 启用压缩
  • 使用缓存
  • 延迟加载
  • 预加载关键资源
  • 内联关键CSS

2. 如何优化渲染性能?

  • 减少DOM操作
  • 避免重排和重绘
  • 使用transform和opacity
  • 使用will-change
  • 使用硬件加速

3. 什么是FCP、LCP、FID、CLS?

  • FCP: 首次内容绘制
  • LCP: 最大内容绘制
  • FID: 首次输入延迟
  • CLS: 累积布局偏移

4. 如何优化图片?

  • 使用合适的格式(WebP)
  • 使用响应式图片
  • 懒加载图片
  • 压缩图片

5. 什么是防抖和节流?

  • 防抖: 延迟执行,只在最后一次触发后执行
  • 节流: 限制执行频率,固定时间间隔执行

通过理解性能优化的各种技术和最佳实践,可以创建高性能的Web应用。

好好学习,天天向上