动态页游客户端性能瓶颈突破:重构帧率天花板
|
我原以为是渲染线程被 canvas lock 住了——结果不是。那天早上八点二十三分,监控报警跳出来,灰度区帧率断崖式掉到 12fps,白屏率翻了四倍,我正啃着凉掉的包子,产品在群里甩来截图:“这版比上上周还卡,你确定测过?”她发完立刻撤回,补了一句“不是质疑你”,妈的,越补越像质疑。 编译进度条卡在 87% 那儿不动,就卡着,像块焊死的铁皮。我盯了三分钟,手欠点了下重试,它才动——但不是跑完了,是重头开始。旁边工位的风扇声突然大起来,嗡嗡嗡,低频震得耳道发痒,我摘了耳机又戴回去,戴反了,左边进右耳。没力气换。 动态页游客户端性能瓶颈突破:重构帧率天花板……这标题我写在周报里时自己都愣了一下,太响。但你说它站不站得住?站得住。不是因为技术多漂亮,是优胜劣汰——设计提了三版粒子动效,后端加了两层服务端预合成,我们客户端这边,要么干掉所有中间帧、要么干掉所有兼容兜底、要么干掉所有离线缓存逻辑。没得选。最后砍掉的不是功能,是「可能性」。删掉 WebWorker 路由同步那块时,我心里空了一下,那代码是我十年前写的,当时觉得牛逼透了。 外卖到了。我听见塑料袋刮门框的声音,没人应,配送员把袋子塞进门缝底下,油渍蹭在门沿上。我没动,继续看 profile——不是主线程卡,是 requestIdleCallback 被一堆低优先级的埋点上报塞满了。谁写的那个「用户行为采样器」?就是上次灰度崩掉后临时加的?那个每帧调三次 getBoundingClientRect 的家伙,现在还在用?
文章配图,仅供参考 烦。真烦。不是烦问题,是烦那种「知道它在那儿,但得假装不知道」的状态。去年年底我们做过一次全量替换 WebGL 渲染器的尝试,跑了七天,最后 rollback,理由是“低端机启动白屏率+0.3%”。0.3%,连埋点误差带抖动都盖不住,但就是卡死了。这次我们没测低端机——直接不保。声明写在 release note 第二行:“Chrome 115+、Safari 17+、无 WebKit 旧内核兜底”。设计看了说“那 iPhone XS 呢”,我说“XS 用户刷抖音都卡,咱这游戏还配播广告吗”,她笑了,后端插嘴:“我们接口都做熔断了,你们客户端还在保 iOS 14?”——这句话我记到现在。我原以为重构帧率天花板是算法的事。结果发现根本不是。是时机。是取舍节奏。是你敢不敢在 build 阶段就把某类 DOM 事件监听器静态抹掉——不是 on-off,是编译期剔除。webpack plugin 写了三版,第二版能跑,第三版才真正让 requestAnimationFrame 得到呼吸权。第一版我写了整整两天,改了三版,熬到凌晨四点,发现它把所有自定义事件也顺手清了,登录态丢了。第二天中午我在茶水间看见设计抱着杯咖啡发呆,问她怎么了,她说“刚改完 UI 动效规范,把弹窗飞入延迟从 200ms 拉到 160ms,产品经理没吭声”。我差点笑出声——160ms?那是三帧半。我们刚把一帧砍到 13ms 以内,人家在抠半帧。 窗外在下雨。不是哗啦啦那种,是那种闷着气的、黏糊糊的冷雨,玻璃上全是斜的水痕。我把 window.location.replace 改成 location.assign 那天,也是这种天。就为绕开一个历史路由栈的内存泄露——不改不行,但改了之后安卓 WebView 下 history.state 突然为空,闪退。修了两天,最后靠 patch window.history.pushState 实现的,贼脏,但跑起来了。这事儿我没往周报里写,怕人说“为什么不早干”。早干?早干的时候没人信“帧率不是算出来的,是挤出来的”。 对了,招聘系统下周要上线新筛简历逻辑,HR 说想让我们帮忙看看性能——我建议他们先关掉自动播放的 GIF banner。真的,关掉。别跟我扯转化率,那东西和帧率一样,表面是数据,底下全是妥协。前两天吃饭听见两个实习生聊“要不要学 Rust 写前端”,我扒拉饭说“先学怎么让 setTimeout(0) 不卡住 RAF”。说完我自己都笑了,哪有那么教人的。 所以现在呢?帧率上限确实是抬了。从“勉强跑满 30”变成“稳在 55~58”之间,偶发跳 60——但不是连续的,是脉冲式的。我们没做到 60 恒定,也不打算做。因为只要有人加个 new AudioContext(),或者某次 V8 GC 正好撞上 drawImage,它就会往下掉。这玩意儿不是工业流水线。它是活的。你只能养,不能焊。 下一步?先把动画控制器里的 easing 表查表逻辑砍掉,改插值计算——不缓存,实时算。反正我们已经不保 IE,也不保老安卓,更不保那些“按住 Home 键再切回来”的野路子操作。至于兼容性列表?等哪天产品经理把“iOS 15.2 上文字模糊”这种 bug 单标成 P0,我们再开个会吧。现在?先让 canvas 别抢 input 事件的锁。 ……等等,我是不是刚说了“canvas lock”?不对,不是 lock,是 collision detection 那块用了太多 offscreenCanvas 传图——传的是完整帧,不是差分区域。这个我回头得重捋。先吃口包子,凉透了,但还能咬。 (编辑:我爱资讯网) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |




