Cocos Creator JavaScript中cc.resources.load回调不生效,外部无法读取修改后的属性值
问题原因
cc.resources.load()是异步加载API,调用后不会立刻执行回调,会先继续执行回调后面的同步代码。你在回调外部读取参数时,资源还没加载完成,回调函数还没触发,参数还没被修改,所以读到的是初始值,并不是修改没生效。
另外还有一种小概率原因:回调函数没有使用箭头函数,导致内部this指向不是当前组件实例,赋值的其实是其他对象的属性,自然不会修改到组件的properties参数。
你提供的代码截图参考:
错误写法复现
properties: { targetRes: null // properties定义的参数 }, start () { // 调用资源加载 cc.resources.load('textures/testImg', cc.SpriteFrame, function (err, res) { // 此处如果没用箭头函数,this指向错误,就算指向正确,执行时机也晚于下面的log this.targetRes = res }) // 此处同步执行,早于回调触发,读到的还是初始值null console.log(this.targetRes) }
解决方案
- 方案1:逻辑内移
所有需要用到修改后参数的逻辑,全部放到加载回调内部执行,保证参数赋值完成后再运行相关逻辑,同时注意用箭头函数保留组件this指向:
如果你坚持用普通函数作为回调,需要提前存储this指向:cc.resources.load('textures/testImg', cc.SpriteFrame, (err, res) => { if (err) { console.error('资源加载失败', err) return } this.targetRes = res // 后续用到targetRes的逻辑都写在这里 this.getComponent(cc.Sprite).spriteFrame = this.targetRes })let self = this cc.resources.load('textures/testImg', cc.SpriteFrame, function (err, res) { if (err) return self.targetRes = res // 后续逻辑写在这里 }) - 方案2:async/await异步转同步写法
用Promise封装加载方法,用async/await语法让异步代码按同步顺序执行,更方便维护多异步串联的逻辑:// 封装通用加载方法 loadAsset (path, assetType) { return new Promise((resolve, reject) => { cc.resources.load(path, assetType, (err, res) => { err ? reject(err) : resolve(res) }) }) }, // 调用的生命周期方法或自定义方法加async修饰 async start () { try { // await会等待加载完成再执行后续代码 this.targetRes = await this.loadAsset('textures/testImg', cc.SpriteFrame) // 此处已经完成赋值,可以正常读取 console.log(this.targetRes) } catch (e) { console.error('加载出错', e) } } - 方案3:事件通知
如果需要跨方法、跨组件使用这个参数,可以在赋值完成后发送自定义事件,监听事件的位置再读取参数执行逻辑:// 回调内赋值完成后发送事件 cc.resources.load('textures/testImg', cc.SpriteFrame, (err, res) => { if (err) return this.targetRes = res this.node.emit('res-loaded') }) // 其他位置监听事件后再读取 onEnable () { this.node.on('res-loaded', this.onResLoaded, this) }, onResLoaded () { console.log(this.targetRes) // 已完成赋值,读取正常 }
注意事项
不要依赖异步操作的执行顺序,所有依赖异步结果的逻辑都要保证在异步完成后触发。
内容的提问来源于stack exchange,提问作者yilin cai
相关产品推荐
相关产品推荐

