如何提高前端应用的性能
1. 代码优化
1.1 减少DOM操作
for(let i=0; i<100; i++) {
document.body.innerHTML += `<div>${i}</div>`;
}
const fragment = document.createDocumentFragment();
for(let i=0; i<100; i++) {
const div = document.createElement('div');
div.textContent = i;
fragment.appendChild(div);
}
document.body.appendChild(fragment);
1.2 事件委托
document.querySelectorAll('.item').forEach(item => {
item.addEventListener('click', handler);
});
document.querySelector('.container').addEventListener('click', (e) => {
if(e.target.classList.contains('item')) {
handler(e);
}
});
2. 资源优化
2.1 图片优化
<img data-src="image.jpg" class="lazyload" alt="">
<script>
const observer = new IntersectionObserver((entries) => {
entries.forEach(entry => {
if(entry.isIntersecting) {
const img = entry.target;
img.src = img.dataset.src;
observer.unobserve(img);
}
});
});
document.querySelectorAll('.lazyload').forEach(img => observer.observe(img));
</script>
2.2 代码分割
const module = await import('./module.js');
3. 网络优化
3.1 启用HTTP/2
server {
listen 443 ssl http2;
# 其他配置...
}
3.2 使用CDN
<script src="https://cdn.example.com/library.js"></script>
4. 渲染优化
4.1 使用虚拟列表
import { FixedSizeList as List } from 'react-window';
const Row = ({ index, style }) => (
<div style={style}>Row {index}</div>
);
const Example = () => (
<List
height={500}
itemCount={1000}
itemSize={35}
width={300}
>
{Row}
</List>
);
4.2 避免强制同步布局
function resizeAllParagraphs() {
for(let i=0; i<paragraphs.length; i++) {
paragraphs[i].style.width = box.offsetWidth + 'px';
}
}
function resizeAllParagraphs() {
const width = box.offsetWidth;
for(let i=0; i<paragraphs.length; i++) {
paragraphs[i].style.width = width + 'px';
}
}
5. 缓存策略
5.1 Service Worker缓存
if('serviceWorker' in navigator) {
navigator.serviceWorker.register('/sw.js');
}
self.addEventListener('install', (event) => {
event.waitUntil(
caches.open('v1').then((cache) => {
return cache.addAll([
'/',
'/index.html',
'/styles.css',
'/app.js'
]);
})
);
});
5.2 合理设置HTTP缓存头
location ~* \.(js|css|png|jpg|jpeg|gif|ico)$ {
expires 1y;
add_header Cache-Control "public";
}
6. 性能监控
6.1 使用Performance API
performance.mark('start');
performance.mark('end');
performance.measure('measure', 'start', 'end');
console.log(performance.getEntriesByName('measure')[0].duration);
6.2 使用Web Vitals
import {getCLS, getFID, getLCP} from 'web-vitals';
getCLS(console.log);
getFID(console.log);
getLCP(console.log);
7. 构建优化
7.1 Tree Shaking
module.exports = {
optimization: {
usedExports: true,
},
};
7.2 代码压缩
const TerserPlugin = require('terser-webpack-plugin');
module.exports = {
optimization: {
minimize: true,
minimizer: [new TerserPlugin()],
},
};
8. 移动端优化
8.1 减少重绘回流
.element {
width: 100px;
height: 100px;
transition: all 0.3s;
}
.element:hover {
width: 200px;
height: 200px;
}
.element {
width: 100px;
height: 100px;
transition: transform 0.3s;
}
.element:hover {
transform: scale(2);
}
8.2 优化触摸事件
document.addEventListener('touchstart', onTouchStart, {passive: true});
9. 框架优化
9.1 React性能优化
const MyComponent = React.memo(function MyComponent(props) {
});
const memoizedValue = useMemo(() => computeExpensiveValue(a, b), [a, b]);
const memoizedCallback = useCallback(() => {
doSomething(a, b);
}, [a, b]);
9.2 Vue性能优化
<div v-once>{{ staticContent }}</div>
computed: {
filteredList() {
return this.list.filter(item => item.active);
}
}
10. 持续优化
10.1 性能预算
"performance": {
"budgets": [
{
"resourceType": "script",
"budget": 100
},
{
"resourceType": "image",
"budget": 70
}
]
}
10.2 A/B测试
window.dataLayer = window.dataLayer || [];
function gtag(){dataLayer.push(arguments);}
gtag('js', new Date());
gtag('config', 'GA_MEASUREMENT_ID', { 'optimize_id': 'OPT_CONTAINER_ID' });