优化FMP到85分后页面反而卡得要命怎么办?
我在优化FMP时提前加载了所有首屏元素,LCP和FMP分数都上来了,但页面交互卡得要命。比如这个React组件用了Intersection Observer预加载图片,但滚动时CPU飙到90%。
尝试过把图片用img标签直接写在HTML里,但发现首页10张大图同时加载导致主线程阻塞。后来改用懒加载,但FMP分数又掉到60分以下。控制台还报了Long Tasks警告。
// 问题代码示例:在useEffect里强行预加载
useEffect(() => {
const preloadImages = document.querySelectorAll('.lazy');
preloadImages.forEach(img => {
img.style.opacity = 1;
img.src = img.dataset.src;
});
}, []);
现在FMP分数和用户体验完全矛盾,是不是预加载策略有问题?怎么平衡评分和实际性能?
根本矛盾是:评分工具只看“首屏内容什么时候显示”,但不管你是怎么加载的;而用户感知的是整个页面流畅度。你提前加载全部首屏元素,相当于让浏览器在首页启动时处理十张高清图解码+渲染,CPU不飙高才怪。
解决方案不是二选一,而是分层加载:
第一,别在useEffect里直接操作DOM去预加载。改用
![]()
原生懒加载,配合只预加载真正关键的1-2张图(比如首屏大banner),剩下的交给Intersection Observer按需触发。第二,给Observer加节流和阈值:
第三,图片本身要做优化:WebP格式 + 设置width/height防止重排 + 用CSS transform做opacity动画避免layout thrashing。
最后记得开启React的并发模式,让渲染不阻塞主线程。你会发现FMP稳定在75-80之间,用户滚动丝滑,Long Tasks消失。分数不是越高越好,真实体验才是终点。
FMP和LCP这些指标确实重要,但你不能一股脑把所有资源塞到主线程里,尤其是图片这种重资源。你现在的做法是在useEffect里一次性触发所有.lazy图片加载,这等于说在组件挂载时强制执行一个高并发的资源加载任务。你没看到主线程卡顿才怪。
解决思路其实不复杂:
1. 降低并发加载数量
别一口气全加载,可以先加载真正首屏的,往下滚动一点再加载后续的。Intersection Observer本来就是干这事的,你用反了。
2. 图片分批次加载 + 占位符优化
给图片加个loading状态,先展示骨架屏或者低分辨率缩略图,等图片加载完成再替换。这样用户感知上不会觉得卡。
3. 拆分Long Tasks
如果你非得在useEffect里做预加载,记得用setTimeout或者requestIdleCallback来切分任务,避免阻塞主线程。
举个优化后的例子:
4. 图片优化本身也要做
- 压缩图片大小,用WebP格式
- 给不同的设备尺寸准备srcset
- 服务端支持图片动态裁剪
5. 性能监控和用户感知分离
FMP这种指标只是参考,真正重要的是用户觉得流畅。你可以通过一些埋点来监控首次可交互时间(TTI)、长任务数量(Long Tasks),这些更能反映真实体验。
总之,别被分数绑架了。优化性能是权衡的艺术,不是谁分数高谁就赢了。你现在这个加载策略明显太激进,稍微缓一缓、分个批,性能就能明显改善。