加快 h5 场景进入速度

前言 - H5 中不可避免的异步资源问题

在和 HTML 打交道的时候,不可避免的会陷入到异步加载的问题里面。比如,有时候需要显示一张图片,我们写上一个 img 标签

<body>
  <img src="http://m.baidu.com/static/index/plus/plus_logo.png" />
  <span>我是占位字符串</span>
<body>

乍一看好像没有什么问题。但是如果用户的网速不能够在 16ms 内加载完毕这张 png 图片,大家就能发现整个页面抖动了一下。
因为页面渲染的时候,这个 img 没有任何数据,宽高都为 0,而等到加载完毕后,页面被动的重新渲染。

纹理绘制与预加载

在 canvas 绘制出一个纹理,就需要事先拿到这个纹理的数据:

var img = document.createElement('img');
img.src = 'xxx';
context.drawImage(img);

这样做就可以了么?这么做的话绘制不出任何图形,因为绘制的时候 img 的数据并没有准备就绪。我们需要等待 img 加载完毕才能够绘制出我们需要的图形:

img.addEventListener('load', function () {
  context.drawImage(img);
});

因为这个原因,cocos 在设计之初,加入了一个预加载队列,用于保证场景在初始化的时候所需要的纹理都已经准备就绪:

cc.LoaderScene.preload([/*资源队列*/], function () { /*游戏逻辑*/ });

这样做的确很友好,在游戏逻辑内不再需要注意资源是否加载完毕,填入资源队列,cocos 就会自动将资源加载进来,保证加载完毕后才会初始化游戏,放心大胆的就可以直接使用了~~啊哈哈。

实际环境可能不允许大量预加载

引擎自动加载挺好的,保证了游戏的纹理的正常绘制。
但是有时候因为自己的实际环境,预加载可能造成场景进入缓慢。。。

场景:

游戏使用 CDN 加速个别不是很重要的图标,但是CDN服务提供商不是很靠谱,间歇性抽风,有时候1个小按钮加载个几十秒,整个游戏就卡在了场景加载页面上。。。

我滴个神啊。。。场景进入拖个几分钟这显然不能接受。。。
cocos2d-js 的 sprite 不是可以设置不存在的图片,过后加载完毕后再自动显示的么?
果断删之。。。
将图标的 png 从资源队列里面删除,进入场景速度瞬间就变快了有木有~~

如果不预加载,会造成什么问题?肿么解决?

刚刚说到受不了加载速度慢,而把预加载的资源队列删除了,这时候会出现什么情况?

  • 画面闪烁:
    因为进入场景的时候,图片数据还没有准备就绪,这时候画面是空的,等到图片加载成功后,画面出现了。。。所以我们还是尽量将吸引注意力的图片加入预加载队列,比如背景图片。。。

  • 资源错位:
    有部分的功能要求在初始化的时候能够取到 sprite 的宽高,比如 ccui 的相对定位等,如果这时候没有预加载图片资源,就会造成计算的位置出现偏差。解决方法很简单,如果发现了资源错位,将错位的资源预加载一下就行了。

  • 资源显示错误:
    在 ccui 中使用 imageView,然后手动设置一张没有预加载的纹理,这时候有可能会被默认的纹理覆盖。。。
    这是由于资源都没有加载,这时候是乱序的,并不能保证哪张图片先加载完毕,哪张后加载完毕。这时候只要将默认图片预加载一下就行了。。。

  • 控制台直接报错:
    =.= 这个,额,这个,我们还是加载一下引起报错的文件吧。。。顺带记得在 github 提交一个 issue,让大大们有机会修复下这些个悲剧~~

看完上面这些,我们可以放心的删除预加载队列啦~~~
唰唰唰~~~~~

必须要预加载的文件

纳尼。。。为啥删了两个文件就报错了 ??
T.T 原来还有文件必须要预加载的啊:

  • plist 合图的配置文件
  • json 各种 json 都是必须要在使用前加载进来的
  • fnt 字体文件,字体因为效率和H5上的限制问题并不会频繁的重绘,所以必须要在绘制前加载完字体
  • tilemap 的图片资源,因为实现问题,必须要在使用的时候能够正常取到宽高,所以必须要预加载

大概就是~除了图片和音频,其余的都需要预加载~~
不过好像其他的也没多大了~~啊哈哈,场景加载速度已经起飞了~

最后总结一下下

我们可以根据需求,适当的删减预加载的资源,将一些不重要的资源去除,以达到加快场景进入速度的目的。
具体的加载队列需要根据自己的游戏,平衡一下会出现的问题,在保证游戏品质的情况下进行。

推荐是先全部预加载,最后阶段再尝试删除精简一下加载队列。

cc.LoaderScene.preload([/*资源队列 - 不要抛弃我 T.T */], function () { /*游戏逻辑*/ });
1赞

Menu 的注意事项:

如果 menu 内的 item 元素没有预加载,并且设置了对其方式(alignItemsHorizontally|alignItemsVertically)。千万注意 item 不能被修改坐标值。action 之类的都不要直接用在 item 上。

因为 menu 重新计算坐标的时候,会重新给x,y赋值。然后就可能出现奇奇怪怪的冲突~

6天了,我来给你挽尊。。。

现在是一个月了~~~

1赞

收藏了,谢谢

cc.LoaderScene.preload([/*资源队列 - 不要抛弃我 T.T */], function () { /游戏逻辑/ }); 貌似没有这个接口 。。。。。