渐进式性能优化策略
性能优化的核心目标
性能优化的核心在于平衡资源消耗与用户体验。过度优化可能导致开发成本上升,而优化不足则会影响用户留存。关键在于找到关键性能指标(如首次内容绘制、交互响应时间)并针对性地改进。
性能基准测量
// 使用Performance API获取关键指标
const measurePerf = () => {
const [entry] = performance.getEntriesByType('navigation');
console.log('TTFB:', entry.responseStart - entry.requestStart);
console.log('FCP:', entry.domContentLoadedEventStart);
console.log('LCP:', performance.getEntriesByName('largest-contentful-paint')[0].startTime);
};
window.addEventListener('load', measurePerf);
真实场景中需要建立持续监控系统,推荐使用:
- Chrome DevTools的Lighthouse面板
- WebPageTest.org的多地点测试
- 真实用户监控(RUM)工具如Sentry
静态资源优化策略
图片渐进式加载
<img
src="placeholder.jpg"
data-src="full-image.jpg"
class="lazyload"
alt="示例图片"
/>
<script>
document.addEventListener("DOMContentLoaded", () => {
const lazyImages = [].slice.call(document.querySelectorAll("img.lazyload"));
if ("IntersectionObserver" in window) {
const lazyImageObserver = new IntersectionObserver((entries) => {
entries.forEach((entry) => {
if (entry.isIntersecting) {
const lazyImage = entry.target;
lazyImage.src = lazyImage.dataset.src;
lazyImage.classList.remove("lazyload");
lazyImageObserver.unobserve(lazyImage);
}
});
});
lazyImages.forEach((lazyImage) => {
lazyImageObserver.observe(lazyImage);
});
}
});
</script>
字体加载优化
@font-face {
font-family: 'CustomFont';
src: url('font.woff2') format('woff2'),
url('font.woff') format('woff');
font-display: swap;
font-weight: 400;
}
关键策略:
- 使用font-display: swap避免布局偏移
- 预加载关键字体:
<link rel="preload" href="font.woff2" as="font" crossorigin>
- 子集化字体文件(如使用glyphhanger工具)
代码分割与懒加载
动态导入实践
// 路由级代码分割
const ProductPage = () => import('./pages/ProductPage.vue');
// 组件级懒加载
const ChatWidget = () => ({
component: import('./components/ChatWidget.vue'),
loading: LoadingComponent,
delay: 200 // 延迟显示loading
});
// 使用webpack魔法注释
import(/* webpackPrefetch: true */ './analytics.js');
Webpack分包策略
// webpack.config.js
optimization: {
splitChunks: {
chunks: 'all',
maxSize: 244 * 1024, // 244KB
cacheGroups: {
vendors: {
test: /[\\/]node_modules[\\/]/,
priority: -10
},
default: {
minChunks: 2,
priority: -20,
reuseExistingChunk: true
}
}
}
}
运行时性能优化
虚拟滚动实现
function VirtualList({ items, itemHeight, containerHeight }) {
const [scrollTop, setScrollTop] = useState(0);
const startIdx = Math.floor(scrollTop / itemHeight);
const endIdx = Math.min(
items.length - 1,
startIdx + Math.ceil(containerHeight / itemHeight)
);
return (
<div
style={{ height: containerHeight, overflow: 'auto' }}
onScroll={(e) => setScrollTop(e.target.scrollTop)}
>
<div style={{ height: items.length * itemHeight }}>
{items.slice(startIdx, endIdx + 1).map((item, i) => (
<div
key={startIdx + i}
style={{
height: itemHeight,
position: 'absolute',
top: (startIdx + i) * itemHeight
}}
>
{item}
</div>
))}
</div>
</div>
);
}
动画性能优化
/* 优先使用transform和opacity */
.box {
will-change: transform; /* 提前告知浏览器 */
transform: translateZ(0); /* 强制硬件加速 */
transition: transform 0.3s ease-out;
}
/* 避免布局抖动 */
.animated-element {
position: fixed;
/* 或者 */
position: absolute;
}
缓存策略进阶
Service Worker缓存策略
// sw.js
const CACHE_NAME = 'v1';
const OFFLINE_URL = '/offline.html';
self.addEventListener('install', (event) => {
event.waitUntil(
caches.open(CACHE_NAME)
.then((cache) => cache.addAll([
'/styles/main.css',
'/scripts/app.js',
OFFLINE_URL
]))
);
});
self.addEventListener('fetch', (event) => {
if (event.request.mode === 'navigate') {
event.respondWith(
fetch(event.request)
.catch(() => caches.match(OFFLINE_URL))
);
} else {
event.respondWith(
caches.match(event.request)
.then((response) => response || fetch(event.request))
);
}
});
ETag优化实践
# nginx配置
location ~* \.(js|css|png|jpg|jpeg|gif|ico)$ {
expires 1y;
add_header Cache-Control "public, no-transform";
etag on;
}
构建时优化
Tree Shaking深度配置
// babel.config.js
module.exports = {
presets: [
['@babel/preset-env', {
modules: false, // 保留ES模块语法
targets: '> 0.25%, not dead'
}]
],
plugins: [
['@babel/plugin-transform-runtime', {
corejs: 3
}]
]
};
// package.json
{
"sideEffects": [
"*.css",
"*.scss",
"@babel/polyfill"
]
}
可视化分析工具
# 生成分析报告
webpack --profile --json > stats.json
# 使用分析工具
npx webpack-bundle-analyzer stats.json
网络层优化
HTTP/2服务器推送
# nginx配置
http2_push /static/js/main.js;
http2_push /static/css/styles.css;
# 或者通过Link头部
add_header Link "</static/js/main.js>; rel=preload; as=script";
QUIC协议优化
# 启用HTTP/3
listen 443 quic reuseport;
listen [::]:443 quic reuseport;
add_header Alt-Svc 'h3=":443"; ma=86400';
渲染性能优化
避免强制同步布局
// 反模式 - 引起布局抖动
function resizeAllParagraphs() {
for (let i = 0; i < paragraphs.length; i++) {
paragraphs[i].style.width = box.offsetWidth + 'px';
}
}
// 优化方案
function resizeAllParagraphs() {
const width = box.offsetWidth;
requestAnimationFrame(() => {
for (let i = 0; i < paragraphs.length; i++) {
paragraphs[i].style.width = width + 'px';
}
});
}
使用content-visibility
.long-list {
content-visibility: auto;
contain-intrinsic-size: 500px; /* 预估高度 */
}
.hidden-section {
content-visibility: hidden; /* 比display:none性能更好 */
}
移动端专项优化
触摸事件优化
// 使用passive事件监听器
document.addEventListener('touchstart', onTouchStart, {
passive: true
});
// 避免300ms点击延迟
<meta name="viewport" content="width=device-width, initial-scale=1.0">
内存管理策略
// 避免内存泄漏
window.addEventListener('load', () => {
const app = new App();
window.addEventListener('beforeunload', () => {
app.cleanup(); // 手动清理
app = null;
});
});
// 使用WeakMap存储大对象
const largeData = new WeakMap();
largeData.set(targetElement, bigData);
性能优化文化构建
建立性能预算机制:
- 关键资源大小限制(如主JS不超过170KB)
- 第三方脚本数量限制(不超过5个)
- 最大DOM节点数(如1500个)
// 在CI中集成性能测试
module.exports = {
ci: {
collect: {
staticDistDir: './dist',
numberOfRuns: 3
},
assert: {
assertions: {
'categories:performance': ['error', {minScore: 0.9}],
'first-contentful-paint': ['error', {maxNumericValue: 2000}]
}
}
}
};
本站部分内容来自互联网,一切版权均归源网站或源作者所有。
如果侵犯了你的权益请来信告知我们删除。邮箱:cc@cccx.cn
上一篇:性能优化中的常见误区
下一篇:性能与功能开发的平衡