九天雁翎的博客
如果你想在软件业获得成功,就使用你知道的最强大的语言,用它解决你知道的最难的问题,并且等待竞争对手的经理做出自甘平庸的选择。 -- Paul Graham

HTML5 游戏的 loading 速度优化

据说以前的页游的 loading 时间一旦超过 5 秒, 就会流失大量用户, 现在的微信 H5 游戏既然也是页游, 既然也想很好的利用网页游戏不用安装, 即点即玩的好处, 对 loading 的要求应该也是一样的. 最近优化了一下我们的游戏, 用到了一些手段, 这里收集整理如下.

目录:

调试和验证方法

  1. 在 chrome 中开启 developer 工具后, 选择 Network, 查看每个资源载入的时间和大小, 用于查看各个资源的大小和载入时间, 可以排序选择最大的入手.
  2. 在 chrome 中开启 developer 工具后, 选择 Timeline, 然后刷新网页, 会自动 record, 出现比较直观的时间流程图, 可以看到各个脚本应该并行加载的时候正的并行, 看到每次 HTTP 的交互是否是必要的, 是否可以合并.
  3. 自己在各个程序运行的关键点输出时间, 主要用于脚本载入以后, 脚本执行初始化流程, 包括登录验证等逻辑流程, 直到游戏画面正常出现过程中的优化.

减少初始资源的载入大小

这个是最核心和关键的因素. 你 loading 10M 的资源, 怎么优化也优化不过只 loading 10K 的.

这里特别明确一下的目的, 我们需要的是将玩家进入游戏的 loading 等待之间尽量缩短, 也就是说, 把进入游戏前 loading 的资源尽量缩小就好了, 进入游戏以后, 再异步 loading 的资源和原来其实差不多大, 但是玩家进入游戏的体验还是提升了.

图片资源, 游戏配置文件, UI 布局文件, 都只 loading 游戏启动必要的部分, 其他可以留到需要的时候再加载.

代码本身, 在稍微大规模项目中, 在将图片和配置减少到一定程度, 代码反而会成为最大的资源, 目前没有特别好的优化手段, 考虑过将代码模块化, 特别是 UI 部分的代码, 实现 UI 操作的时候动态载入运行, 理论上可行, 没有验证.

这里比较尴尬的是显示 loading 进度的背景图本身的问题, 这个图本身的加载就需要时间, 所以我建议尽量精简这个图片本身的大小. 作为更激进的做法, 很多游戏实际是没有 loading 图的, 而是用 1 / 100 这样的纯数字来表示. 这个之间的权衡, 就看各个项目本身的情况了.

源代码和 json 文件的压缩

最简单的办法是利用 http server(或者 CDN) 的 gzip 压缩功能,

首先 CDN 需要支持和开启 gzip 压缩, 并且在源栈配置好合适的类型, javascript 的源代码 和 json(配置) 都是可以通过 gzip 压缩的, 效果明显. 关于源栈, 我们就碰到过 nginx 服务器不自动识别 json, 导致原来的 json 配置都没有压缩的问题.

看 headers 的话, js 是 Content-Encoding:gzip Content-Type:application/x-javascript

json 是 Content-Encoding:gzip Content-Type:application/json

表示已经开启了 gzip 压缩, 实际传输大小可以减少很多.

也可以直接在 chrome 的 network 里面打开 Content-Encoding 列, 然后看此列是否有 gzip 标志.

另外, 假如真的有更高的要求, 也是可以自己压缩源代码和 json 文件的, 这样你可以选择用比 gzip 压缩比更高的压缩算法, 不过, 注意 javascript 本身的运行效率, 别用太慢的压缩算法. 比如 jszip 这个库.

减少 http 的交互次数

因为 http 的交互比较慢, 减少交互的次数可以显著提高载入速度.

对于图片, 载入期必要图片都应该打包成图集, 最好是能打包成 1 个文件, 我们项目中最后做到了, 我命名为 gamemin, 这个图集可以进一步的考虑压缩, 比如使用 png8 格式. 因为最后的大小已经在 150K 的水平了, 没有进一步的使用诸如 webp 等压缩比更大的图片格式, 有更严格要求和追求的话, 可以考虑, 不过需要测试一下对应的 javascript 解码库的效率.

游戏配置, 成规模的项目, 又是策划写 excel 导出的话, 往往有几十个, 可以合并成一个, 去掉空格换行等. 为此我写了个合并工具: json_compacker

egret 库的合并

在新的 egret 中, 进行了模块化的设计, 每个模块可以单独选择是否添加, 但是这样一来, 原来只需要 loading 一个库, 现在需要 loading 好几个, 实际是划不来的, 而 egret 官方没有提供官方的解决方案.

合并 js 的工具不少, 不过我在官方论坛上找到一个, 使用是最方便的. 合并 egret 库的工具

脚本加载的精确控制

首先, 在我们游戏中有个例子, 就是接入了很多平台, 原来的做法是所有平台的 sdk 都加载 (你要看平台 SDK 的文档的话, 都是这么教你的), 然后选择性的运行对应的代码. 这样做实际多加载了很多不必要的平台 sdk, 平台这些 sdk 还都是从合作方网站上下载回来的, 我们缺乏控制. 修改后变成首先判断渠道, 然后只加载渠道对应的一个平台 sdk.

动态加载脚本的方法在”高性能 JavaScript”一书中有比较详细的介绍, 简单的说就是可以用下面这两个库:

lazyload LABjs

总结

因为是公司项目, 所以略去的所有相关的源代码, 总体来说, 我用到的优化手段都提到了. 需要说明的是, 优化的时候更多的是在一个完全没有优化的版本上进行的, 随便优化一下, 都能获得比较大的改进, 所以实际工作做的不是足够严谨, 在有多个优化方案时, 都是选择相对简单的那个解决方案, 而不是详细的对比多个方案的实际情况, 经过测试然后选择.(这个才是正确的做法)

分类:  编程 
标签:  HTML5  游戏  javascript 

Posted By 九天雁翎 at 九天雁翎的博客 on 2016年09月13日

前一篇: 发布一个自动为Markdown文章添加目录的工具 后一篇: 小议入门语言对初学者的影响