移动端性能问题排查
场景
移动端 H5 页面出现滚动卡顿、页面打开慢、动画掉帧等性能问题,你怎么排查和优化?
分析思路
移动端特有的性能挑战
| 挑战 | 原因 |
|---|---|
| CPU/GPU 弱 | 移动设备算力远低于桌面端 |
| 内存有限 | 内存不足会触发浏览器 tab 被杀 |
| 网络不稳 | 3G/4G 弱网、地铁信号差 |
| 屏幕小但密度高 | 高 DPR 设备绘制像素多 |
| WebView 兼容性 | 不同厂商内核差异 |
排查工具
远程调试:
注入调试面板
// 开发/测试环境注入
if (process.env.NODE_ENV !== 'production') {
import('vconsole').then(({ default: VConsole }) => {
new VConsole();
});
}
常见问题与优化
问题 1:滚动卡顿
✅ 启用弹性滚动
.scroll-container {
overflow-y: auto;
-webkit-overflow-scrolling: touch; /* iOS 弹性滚动 */
overscroll-behavior: contain; /* 防止滚动穿透 */
}
✅ 触摸事件使用 passive
// 移动端 touch 事件默认非 passive,浏览器要等 preventDefault 判断
document.addEventListener('touchmove', handler, { passive: true });
问题 2:弱网环境加载慢
✅ 检测网络状态并适配
function getNetworkStrategy(): 'fast' | 'slow' | 'offline' {
const conn = (navigator as any).connection;
if (!navigator.onLine) return 'offline';
if (conn) {
if (conn.effectiveType === '4g' && !conn.saveData) return 'fast';
return 'slow';
}
return 'fast';
}
// 根据网络状态调整策略
const strategy = getNetworkStrategy();
if (strategy === 'slow') {
// 加载低质量图片、关闭动画、减少请求
}
if (strategy === 'offline') {
// 使用缓存数据、提示用户
}
问题 3:图片渲染性能
✅ 移动端图片优化
// 根据 DPR 和网络加载合适的图片
function getOptimalImageUrl(baseUrl: string, width: number): string {
const dpr = Math.min(window.devicePixelRatio, 2); // 最大 2x 即可
const physicalWidth = Math.round(width * dpr);
return `${baseUrl}?w=${physicalWidth}&q=75&f=webp`; // CDN 图片处理
}
问题 4:动画掉帧
✅ 只用 transform 和 opacity
/* 移动端动画务必避免触发重排 */
.animated {
transform: translateX(100px); /* ✅ GPU 加速 */
opacity: 0.8; /* ✅ GPU 加速 */
/* ❌ 避免:top, left, width, height, margin */
}
问题 5:内存不足导致页面崩溃
✅ 长列表使用虚拟滚动
// 移动端列表千万别一次渲染上千条 DOM
// 使用虚拟列表只渲染可视区域
// 同时监控内存
if ('memory' in performance) {
const mem = (performance as any).memory;
if (mem.usedJSHeapSize / mem.jsHeapSizeLimit > 0.9) {
console.warn('内存使用率 > 90%,可能崩溃');
}
}
常见面试问题
Q1: 移动端和桌面端性能优化有什么区别?
答案:
移动端要额外关注:CPU/GPU 弱(JS 执行时间更长)、内存有限(虚拟列表更重要)、网络不稳(弱网适配)、触控延迟(passive 事件)、高 DPR 绘制(图片优化)。
Q2: 如何在移动端调试性能问题?
答案:
- iOS Safari 远程调试、Android Chrome
chrome://inspect - 注入 vConsole/Eruda 调试面板
- 使用
performance.mark()/performance.measure()在代码中打点 - Lighthouse 移动端模式