网页游戏是在和「后退按钮」竞争。对慢加载的容忍大约是桌面端一秒、手机端两秒——而这个预算里包括网络、解析、首次绘制,以及第一次可输入的帧。
下面这些都是认真对待这个预算的结果。
三种加载,不是一种
游戏门户有三个不同的加载问题,把它们当成一个是最经典的错误。
- 外壳。 框架、样式、字体。付一次,之后一直走缓存。
- 元数据。 标题、缩略图、分类——渲染一百款游戏列表所需的全部信息。
- 游戏本体。 代码,以及它需要的资源。
混在一起意味着:浏览游戏库的玩家为永远不会运行的代码付费,而只想玩某一款的玩家为整个库付费。
有效的切分是:外壳与元数据全局加载,游戏代码只在打开游戏时加载。游玩页多一次往返,库页面保持很小。
缩略图陷阱
缩略图是游戏门户上最重的东西,也最容易做错。一百款游戏每张 40 KB,就是四兆 JPEG,而网格一次只显示十二个。
修法无聊但有效:按显示尺寸生成 WebP,两种格式都出,首屏以下的全部懒加载。实践中这能把四兆的页面变成两百 KB,肉眼没有区别。
图片比屏幕还大,就是太大了。唯一的例外是它同时还要当社交分享图。
框架的代价
框架不慢,渲染一百个 DOM 节点也不慢。慢的是每次按键都干这两件事,或者用一个每次路由变化都重渲染整棵树的 router。
实践中最贵的模式:
- 滚动时重渲染列表,而列表只在路由变化时才变。
- 字体加载与后备字体度量不一致,字体到达时布局跳一下。
- 为一个过渡效果引入整个动画库。
这些都不是框架问题,而是「我没有测量」的问题。一个页面的成本,就是所有没人 profile 过的东西之和。
预渲染是一个性能特性
静态预渲染页面通常被当作 SEO 特性来讨论,它确实是——但它同时消掉了 Web 应用里最贵的那一刻:JavaScript 到达后的首次渲染。
如果 HTML 里已经有内容,浏览器可以在脚本解析完之前就绘制。这就是本站为每个路由生成真实页面的原因:不只是让搜索引擎看到内容,也是让首次绘制不必等应用启动。
感知速度
预算里有一部分是心理学:
- 骨架屏胜过转圈。 转圈在说「等」,骨架在说「要来的东西长这样」。
- 绘制之后不要再移动内容。 布局跳动会被感知成 bug,而不是「慢」。
- 先启动时钟,再启动关卡。 能立刻显示标题或第一帧的游戏,即使资源还在加载,也会显得即时。
该测什么
四个数字几乎能覆盖一切:
- 首字节时间。
- 首次内容绘制。
- 最重页面的总字节数。
- 首次交互的输入延迟。
这四个都好,游戏就是快的;任何一个差,再多美术方向也遮不住——因为玩家根本没走到能看见美术的地方。