记录: cocos create 2.x版本小游戏平台加载bundle时隐藏的一个坑点

小游戏平台使用bundle加载远端资源同时立即释放bundle包会导致报错, 如下图

// 复现bug代码,复制到小游戏控制台运行
cc.assetManager.loadBundle("Mode180",(err,bundle)=>{
        // 立即加载远程端 prefab
        bundle.load("Mode180",cc.Prefab,(err,k)=>{console.log('load:',err,k)}); 
        // 立即释放bundle 或者没等load Mode180 完成就释放就会触发报错
        bundle.releaseAll(); 
        cc.assetManager.removeBundle(bundle);  
})

这bug会导致内部路径前缀为 undefined
image

bug 特性

  • 隐蔽性: 这bug触发概率比较低, 网速快时候测不出来, 触发错误不会被小游戏平台异常捕获
  • 堵塞加载流程,影响加载速度甚至卡死
  • 恶心网速慢的玩家
  • 潜在内存泄漏
  • 我是怎么发现这个bug的: 在游戏途中加载背景音乐还没完成时, 玩家退出关卡释放音乐所在bundle触发
    如果网络重试次数设置100, 那么这bug会占用大量加载时间最终返回错误, 或者之间卡死流程

bug机制:

bundle.load() 是 异步 的,但你在回调里 同步 执行了 releaseAll() + removeBundle() ,把 bundle 从注册表注销了;等 prefab 的 JSON 下载完成、要拉它的依赖图片/音频(native)时,引擎重新查 cc.assetManager.bundles 查不到这个 bundle → 拿不到 config → 兜底用 cc.assetManager.generalNativeBase (main.js 没传 = undefined)→ 拼出 undefined/xx/xxx.png 这样的 URL → 适配器当本地路径找不到文件 → 报 “file undefined/… does not exist!”(6029)。

undefined来源:

当远端资源下载好后才跑combine函数,这函数作用是组合url路径, 因为bundle释放了所以 config 是空的,所以 base == undefined ,导致拼接前缀是undefined
image

这就是这bug导致的undefined

我认为这不是引擎的问题 是你使用时机有问题导致的 你既然知道有回调是有时间差 ,那么你就不应该设计成这种使用方式,你不去避免问题 反而迎着问题上,那不是你自身的问题吗

你这是站在问题已经发现的视角来说解决方案
不知道这个问题的人怎么办呢

他释放bundle前 就应该做到,bundle里的资源 都应该保证不再被使用了才行,显然他这是自己给自己找问题的,不出错才怪的,这个是JS回调机制的问题 不是引擎的问题,如果做到适当的时机释放资源 是应用层要做好的,显然他没有作对

假设玩家网速慢,进入关卡后音乐正在加载, 加载背景音乐要10s, 此时玩家点击退出到主页或切换关卡, 难道要加载转圈圈等音乐加载完才允许释放资源退出关卡吗 :joy:

要么等 保证不出错 然后正常使用,
要么您就换引擎 有那种随时能中断这个回调过程的功能,来达到这种有强迫症用户的需求