【BabylonJS】异步有坑?异步有坑!记一次报错的发现过程。

先来看下报错的具体内容:

Unable to load assets from /static/model/xx/xx.glb: Scene has been disposed

从字面意义上来看,是场景Scene被释放了,加载资源失败。

为什么会出现这种情况呢?我们先来看下整个的业务流程:

1、进入页面,创建场景1;

2、在页面进行了某些操作,销毁场景1,使用的是scene.dispose

3、执行完dispose之后,然后加载场景2,即重新new一个scene,并加载资源。

报错出现的操作手法是这样的,如果“在页面进行了某些操作”发生时间比较晚,就不出现这个报错,发生的比较早的话,就出现这个报错。如果踩过同样的坑,或者心思缜密的童鞋,可能很快发现了问题。但我今天确实兜了一些弯路。

因为“在页面进行了某些操作”,实际上就是为了加载场景2,并在场景2里面加载资源。在加载场景2的资源的时候,发生了“Scene has been disposed”的报错,正常的思维都是:我这个scene不是刚new出来的吗,怎么会已经被dispose 了呢?

于是我开始怀疑,是不是这个dispose不是同步的,是异步的,开始执行了dispose之后就立马返回了,因为我的代码是这么写的:

scene.dispose();
scene = null;

//---

scene = new BABYLON.Scene();

xxx.LoadAssest(xxx, xxx, scene);   //加载资源。就随意写下伪代码了。

如果dispose是同步的,那么scene = new BABYLON.Scene()就应该是让scene能够重新建立的;出现上面的问题的一种可能就是:dispose不是同步的,它可以立马返回,但dispose的真正操作是后面再进行的,也就变成了如下顺序:

1、dispose方法被调用,立马返回;

2、new了一个新的scene

3、此时dispose真的发挥了作用,scene又被干掉了

4、加载资源,scene已经不存在,报错

是不是完美解释了上述报错,我当时也觉得这个解释真完美,心里还暗暗骂道,怎么这个引擎这么lj...

如果真的是这样,也得解决这个问题呀,解决方案就是要到真正dispose执行完毕之后才能去做上面的第2和第4步。看了下api文档,有个onDispose的响应方法,于是加上,同时打下log检查下实际的执行顺序。

然后我傻眼了:onDispose的响应,的的确确明明白白在“2、new了一个新的scene”前面执行了。

难道onDispose也是不正确的?不至于吧,堂堂这么大一个引擎,如果是有这种问题就真的很lj了。

正当百思不得其解之时,在想是不是要用些什么取巧办法来绕开这个问题。我再次仔细看了下报错,报错语句里面前面半句,是提供了具体要加载的资源的路径。

咦,这个路径,不是我执行完dispose之后,然后加载场景2想要加载的资源哦,应该是“进入页面,创建场景1”时就要加载的资源!

这个时候我恍然大悟了,这个报错里面,已经被dispose的scene,并不是新new出来的scene,而是被我们手动dispose的scene。这个报错引发的过程如下:

1、进入页面,创建场景1,第一个scene,此时加载资源1、资源2、资源3......;

2、资源n开始加载,但还没从服务端下载下来;

3、第一个scene被dispose掉了

4、第二个scene被new 出来了,然后开始加载新的资源A,资源B,资源C,。。。;

5、资源n此时从服务端拉下来了,引擎内部开始加载到场景,也就是第一个scene,然而第一个scene已经被dispose了,于是就报了文章一开始的那个报错。

这也完美解释了为什么如此诡异:如果“在页面进行了某些操作”发生时间比较晚,就不出现这个报错,发生的比较早的话,就出现这个报错。而且这个报错也并不影响页面后续的操作,因为新加载的scene及其资源都是正常的!

整个问题的核心就是babylon内部对于这种资源异步加载的处理还不够到位。dispose本身并没什么问题,冤枉它了。正常来说,像这种情况,资源还没下载下来,scene就被dispose了的情况,正在发送和即将要发送的资源加载请求,应该中断;无法中断,且资源已经加载回来之后,scene被dispose了,也就是爹妈没了,自然而然资源就应该终止它的生命周期。至少我认为完美的处理是如此,毕竟在写法上,资源跟scene是绑定到了一块。不绑定的话,各干各的,就另说了。

整个问题的解决过程便是如此。也有童鞋问了,为什么不是一开始就能发现是第一个scene被dispose掉导致的呢,我觉得在这次的事件里面主要有2个原因:

(1)因为场景1要加载的资源还是比较多,我们把资源url写到了数据库,读取了接口再进行的加载,url这玩意我们就不去写死在代码里,所以对URL并没什么感觉,并不知道哪个资源对应哪个场景的什么状态。

(2)这个报错的发生时机是在我们加载了第二个场景之后发生的,正常的线性思维便是如此,这个时候发生的事情就跟当前这个操作有关。当然段位比较高就能一眼看出哈哈哈哈哈。

总之一句话,异步真的有坑啊。。。。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

程老师2088

您的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值