前端性能优化不是炫技是抠每帧的细节
上周跟个做了六年前端的朋友撸串,他吐槽刚上线的项目被产品追着骂——首屏加载要4.2秒,用户跳出率涨了快两成。他说自己已经把能搬的资源都搬CDN了,还是卡。
我当时啃着烤茄子没接话。我知道他的问题在哪。他从项目立项开始就没把加载节奏当回事,直到上线了才想起要做优化,临时抱佛脚的结果,就是拆包拆得稀碎,一堆小资源挤在网络请求队列里排队,比之前的单包加载还慢。
Chrome DevTools Network面板加载瀑布流截图
你会发现一堆根本不该出现在首屏加载队列里的东西。比如一个1.2MB的未压缩城市列表JSON,是给三级页面的城市选择器用的,结果被放在了入口的依赖里,跟着主包一起加载。比如200多KB的全量图标雪碧图,首屏页面总共才用到3个图标,剩下的图全是白下。还有那个被同步放在head里的第三方统计SDK,明明可以等页面加载完再异步引入,结果被放在了head标签里同步加载,直接把整个渲染流程堵了三秒。
有人说那我把所有非首屏资源都懒加载不就完了?
麻烦在于,懒加载做过头,用户点按钮的时候才开始加载对应组件,那等待的卡顿感,比首屏慢还让人难受。
这里的取舍很简单:你列个清单,把用户进入页面后10秒内大概率会交互的元素挑出来——比如电商详情页的规格选择按钮、文章页的评论输入框、个人中心的头像入口,这些对应的JS和CSS片段,你得提前预热加载,别等用户点了才开始拉。代价是什么?你得多写几百行的预判逻辑,甚至要做简单的用户行为埋点,算清楚哪些路径的点击率超过30%,哪些根本没人碰。但换回来的,是用户点击时的零等待,值不值,你自己算。

浏览器渲染流程中重排重绘触发节点示意图
我之前见过有团队为了把LCP指标压到2秒以内,把整个首屏的JS依赖全删了,用纯静态HTML写页面。结果后面要加个动态的表单提交功能,得重新写一套接口的直连逻辑,多花了两周的开发时间。
这就是代价。没有无成本的性能优化,你想要极致的加载速度,就得放弃一部分前端的交互灵活性,没有什么两全的事。
别上来就拆包,先看你那加载瀑布流漏了什么
很多人一提到前端性能优化,第一反应就是上代码分割、Tree shaking、压缩混淆。动作很快,敲键盘的声音噼里啪啦,结果改完一看,加载速度根本没提上去。 这事没那么玄。 你先打开Chrome DevTools的Network面板,把网速切到3G的模拟环境,重新加载一遍页面,盯着那个从上到下排开的瀑布流看。渲染阶段的坑,从来都不是你写的CSS不够少
我见过太多人优化渲染性能的方式,是把CSS里的空格删掉,把选择器写得尽量短,甚至把所有的CSS都内联在HTML标签里。折腾半天,滚动的时候还是掉帧。 问题根本不在这。 比如你给首屏的一个空div加了个无限循环的阴影动画,从页面加载开始就跑,哪怕用户根本没往下滑到这个位置,这个动画也一直占着GPU的渲染线程,滚动的时候直接卡成PPT。比如你把所有的图片都加了loading=”lazy”,连首屏最核心的banner图也没放过,结果浏览器根本不知道这张图要占多大的空间,等图加载完,整个页面突然往下跳了200像素——这种无预警的布局偏移,是最容易让用户火大的问题。 太烦了。谁遇到这种页面都得骂一句然后退出去。 正确的做法其实很朴素:首屏的核心图,一定要给明确的width和height属性,别让浏览器瞎猜占多大地方。动画能交给GPU处理的,就只用transform和opacity,别用top、left这些属性让浏览器每帧都重新算布局位置。