𝑻𝒆𝒏𝑪𝒍𝒂𝒘正在头脑风暴···
𝑻𝒆𝒏𝑲𝒊𝑺𝒆𝒀𝒂の𝑨𝒈𝒆𝒏𝒕助手
𝑻𝒆𝒏-𝒇𝒍𝒂𝒔𝒉

前端性能优化实战

前端性能优化是提升用户体验的关键。本文将介绍实用的前端性能优化技术和最佳实践,帮助开发者构建更快、更流畅的 Web 应用。

性能指标

1. Core Web Vitals

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

2. 传统指标

  • FCP (First Contentful Paint): 首次内容绘制
  • TTI (Time to Interactive): 可交互时间
  • TBT (Total Blocking Time): 总阻塞时间

3. 测量工具

  • Lighthouse: Google Chrome 开发者工具
  • WebPageTest: 详细的性能分析
  • Chrome DevTools: 实时性能监控

资源优化

1. 图片优化

// 使用 WebP 格式
<picture>
<source srcset="image.webp" type="image/webp">
<img src="image.jpg" alt="Description">
</picture>

// 懒加载
<img src="image.jpg" loading="lazy" alt="Description">

// 响应式图片
<img src="image.jpg"
srcset="image-320w.jpg 320w,
image-640w.jpg 640w,
image-1024w.jpg 1024w"
sizes="(max-width: 320px) 280px, (max-width: 640px) 600px, 800px"
alt="Description">

2. 字体优化

/* 字体加载优化 */
@font-face {
font-family: 'CustomFont';
src: url('font.woff2') format('woff2');
font-display: swap;
}

/* 预加载重要字体 */
<link rel="preload" href="font.woff2" as="font" type="font/woff2" crossorigin>

3. 代码分割

// React 动态导入
const LazyComponent = React.lazy(() => import('./LazyComponent'));

// Vue 异步组件
const AsyncComponent = defineAsyncComponent(() =>
import('./AsyncComponent.vue')
);

网络优化

1. 缓存策略

// Service Worker 缓存
const CACHE_NAME = 'my-app-cache-v1';
const urlsToCache = [
'/',
'/styles/main.css',
'/scripts/main.js'
];

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 => response || fetch(event.request))
);
});

2. HTTP/2 优化

// 启用服务器推送
if ('serviceWorker' in navigator) {
navigator.serviceWorker.register('/sw.js')
.then(registration => {
registration.postMessage({ type: 'SKIP_WAITING' });
});
}

3. CDN 加速

<!-- 使用 CDN 加载静态资源 -->
<link rel="stylesheet" href="https://cdn.example.com/styles/main.css">
<script src="https://cdn.example.com/scripts/main.js"></script>

渲染优化

1. 避免强制同步布局

// 不好的做法
function updateLayout() {
const width = element.offsetWidth;
element.style.height = width * 2 + 'px';
const height = element.offsetHeight;
console.log(height);
}

// 好的做法
function updateLayout() {
requestAnimationFrame(() => {
const width = element.offsetWidth;
element.style.height = width * 2 + 'px';
const height = element.offsetHeight;
console.log(height);
});
}

2. 使用 requestAnimationFrame

function animate() {
// 动画逻辑
element.style.transform = `translateX(${position}px)`;

// 继续动画
requestAnimationFrame(animate);
}

requestAnimationFrame(animate);

3. 虚拟滚动

// 虚拟滚动实现
class VirtualScroll {
constructor(container, items, renderItem) {
this.container = container;
this.items = items;
this.renderItem = renderItem;
this.visibleItems = [];
this.itemHeight = 50;
this.scrollTop = 0;

this.init();
}

init() {
this.container.addEventListener('scroll', () => {
this.scrollTop = this.container.scrollTop;
this.render();
});

this.render();
}

render() {
const startIndex = Math.floor(this.scrollTop / this.itemHeight);
const endIndex = Math.min(
startIndex + Math.ceil(this.container.offsetHeight / this.itemHeight),
this.items.length
);

this.visibleItems = this.items.slice(startIndex, endIndex);
this.container.innerHTML = this.visibleItems
.map((item, index) => this.renderItem(item, startIndex + index))
.join('');
}
}

JavaScript 优化

1. 防抖和节流

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

// 节流
function throttle(func, limit) {
let inThrottle;
return function(...args) {
if (!inThrottle) {
func.apply(this, args);
inThrottle = true;
setTimeout(() => inThrottle = false, limit);
}
};
}

// 使用示例
window.addEventListener('resize', debounce(handleResize, 250));

2. 事件委托

// 不好的做法
document.querySelectorAll('.item').forEach(item => {
item.addEventListener('click', handleClick);
});

// 好的做法
document.querySelector('.container').addEventListener('click', (e) => {
if (e.target.classList.contains('item')) {
handleClick(e);
}
});

3. 内存管理

// 清理事件监听器
function setupComponent() {
const element = document.getElementById('my-element');

function handleClick() {
// 处理点击
}

element.addEventListener('click', handleClick);

// 返回清理函数
return () => {
element.removeEventListener('click', handleClick);
};
}

// 使用
const cleanup = setupComponent();
// 组件卸载时调用
cleanup();

CSS 优化

1. 选择器优化

/* 不好的做法 */
.container .item .content .title {
color: blue;
}

/* 好的做法 */
.content-title {
color: blue;
}

2. 动画优化

/* 使用 transform 和 opacity 进行动画 */
.animated-element {
will-change: transform, opacity;
transition: transform 0.3s ease;
}

.animated-element:hover {
transform: scale(1.1);
opacity: 0.9;
}

3. 减少重绘和回流

/* 使用 visibility 替代 display */
.hidden {
visibility: hidden;
}

/* 使用 transform 替代 top/left */
.movable {
transform: translateX(100px);
}

工具和框架

1. 构建工具优化

// webpack 配置
module.exports = {
optimization: {
splitChunks: {
chunks: 'all',
minSize: 20000,
maxSize: 244000,
minChunks: 1,
maxAsyncRequests: 5,
maxInitialRequests: 3,
automaticNameDelimiter: '~',
cacheGroups: {
vendors: {
test: /[\\/]node_modules[\\/]/,
priority: -10
},
default: {
minChunks: 2,
priority: -20,
reuseExistingChunk: true
}
}
}
}
};

2. 框架优化

// React 优化
import React, { memo, useCallback, useMemo } from 'react';

const OptimizedComponent = memo(({ data, onAction }) => {
// 使用 useMemo 缓存计算结果
const processedData = useMemo(() => {
return data.map(item => ({ ...item, processed: true }));
}, [data]);

// 使用 useCallback 缓存函数
const handleClick = useCallback(() => {
onAction();
}, [onAction]);

return (
<div>
{processedData.map(item => (
<div key={item.id} onClick={handleClick}>
{item.name}
</div>
))}
</div>
);
});

3. 性能监控

// 性能监控
const observer = new PerformanceObserver((list) => {
for (const entry of list.getEntries()) {
console.log(`${entry.name}: ${entry.duration}ms`);
}
});

observer.observe({ entryTypes: ['measure'] });

// 开始测量
performance.mark('start');
// 执行代码
performance.mark('end');
performance.measure('my-operation', 'start', 'end');

实战案例

1. 首屏优化

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

// 懒加载非关键资源
const loadNonCriticalResources = () => {
import('./non-critical.js').then(module => {
module.init();
});
};

// 页面加载完成后执行
window.addEventListener('load', loadNonCriticalResources);

2. 图片懒加载实现

class LazyLoader {
constructor() {
this.images = document.querySelectorAll('img[data-src]');
this.observer = new IntersectionObserver(
this.handleIntersection.bind(this),
{ rootMargin: '50px' }
);

this.init();
}

init() {
this.images.forEach(img => {
this.observer.observe(img);
});
}

handleIntersection(entries) {
entries.forEach(entry => {
if (entry.isIntersecting) {
const img = entry.target;
img.src = img.dataset.src;
img.classList.remove('lazy');
this.observer.unobserve(img);
}
});
}
}

// 初始化
new LazyLoader();

3. Service Worker 缓存策略

const CACHE_NAME = 'my-app-cache-v2';
const ASSETS_URLS = [
'/',
'/index.html',
'/styles/main.css',
'/scripts/main.js'
];

// 安装事件
self.addEventListener('install', (event) => {
event.waitUntil(
caches.open(CACHE_NAME)
.then(cache => cache.addAll(ASSETS_URLS))
);
});

// 激活事件
self.addEventListener('activate', (event) => {
event.waitUntil(
caches.keys().then(cacheNames => {
return Promise.all(
cacheNames.filter(name => name !== CACHE_NAME)
.map(name => caches.delete(name))
);
})
);
});

// 拦截请求
self.addEventListener('fetch', (event) => {
event.respondWith(
caches.match(event.request)
.then(response => response || fetch(event.request))
);
});

前端性能优化是一个持续的过程,需要结合项目实际情况进行优化。通过合理的优化策略,可以显著提升用户体验和应用性能。