性能优化
性能指标
核心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: br4. 使用缓存
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.com3. 使用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应用。