标准周期

http://docs.cocos.com/creator/manual/zh/scripting/life-cycle-callbacks.html

creator提供了7种生命周期函数,分别是:
onLoad,start,update,lateUpdate,onDestroy,onEnable,onDisable
其中:
onDestroy,onEnable,onDisable为触发式调用,可以参考官方文档,此处不说明。
另外4种的调用顺序是onLoad -> start -> update -> lateUpdate

在标准周期中插入方法

结论onload -> test-function -> start -> update = > lateupdate
例子:有1个prefab和挂载在prefab上的脚本test,1个主脚本

  1. // test.ts
  2. const { ccclass, property } = cc._decorator;
  3. @ccclass
  4. export class test extends cc.Component {
  5. onLoad() {
  6. cc.log("onload")
  7. }
  8. start() {
  9. cc.log("start")
  10. }
  11. flag_update = true
  12. update() {
  13. if (this.flag_update) {
  14. this.flag_update = false
  15. cc.log("update")
  16. }
  17. }
  18. flag_late_update = true
  19. lateUpdate() {
  20. if (this.flag_late_update) {
  21. this.flag_late_update = false
  22. cc.log("lateupdate")
  23. }
  24. }
  25. test() {
  26. cc.log("test-function")
  27. }
  28. }
  1. // 主脚本
  2. ******
  3. onLoad() {
  4. this.create_some_node()
  5. }
  6. @property(cc.Prefab)
  7. some_prefab: cc.Prefab = null
  8. create_some_node() {
  9. let n = cc.instantiate(this.some_prefab)
  10. n.parent = this.node
  11. n.getComponent(test).test()
  12. }
  13. ******

拖入后执行,执行的结果为:
微信截图_20190603130625.png

scheduleOnce()update()之前还是之后?

结论update -> scheduleOnce

  1. // 修改脚本 test.ts
  2. ******
  3. onLoad() {
  4. this.scheduleOnce(() => {
  5. cc.log("onload")
  6. }, 0)
  7. }
  8. start() {
  9. this.scheduleOnce(() => {
  10. cc.log("start")
  11. }, 0)
  12. }
  13. ******

执行结果为:
1.png

原理浅析:帧

  1. 游戏内所有的逻辑以帧为基础。
  2. 引擎可以做到渲染帧、逻辑帧、物理帧等分离。cocos-creator中渲染帧和逻辑帧未分离。
  1. // 将test.ts改回去,无schedule
  1. // 修改主脚本,以3帧为例子
  2. ******
  3. onLoad() {
  4. // this.create_some_node()
  5. }
  6. count = 0
  7. update() {
  8. if (this.count < 3) {
  9. cc.log("update:", this.count)
  10. for (let i = 0; i < 1000; i += 1) {
  11. cc.log(1) // 本项目是为了阻塞帧的执行
  12. }
  13. if (this.count === 1) {
  14. this.create_some_node()
  15. }
  16. this.count += 1
  17. }
  18. }
  19. ******

执行结果为:
2.png
可以从结果看出,除了循环会阻碍帧的进程以外,子函数create_some_node也会阻碍帧的进程,并且在此帧内会执行到子脚本的start方法。

优化方向1:减少单帧内的计算,放到多帧去执行

这点的逻辑很容易理解,即将一些无关的计算从单帧放到多帧中去执行。
creator中的api:schedule()中参数interval=0是为间隔帧执行,或者传入时间也可以了。

(错误的)优化方向2:异步化

由于js单线程的原因,即使是异步的promise也会一定程度上的阻塞执行。
在creator中则体现在:在某一帧中使用的promise,一定会在当前帧中执行完毕。

  1. // 清理主脚本,仅创建,无其他调用或者输出
  2. // 修改test.ts
  3. ******
  4. onLoad() {
  5. cc.log("onload")
  6. }
  7. start() {
  8. cc.log("start")
  9. }
  10. count = 0
  11. update() {
  12. if (this.count < 5) {
  13. cc.log("update", this.count)
  14. if (this.count === 0) {
  15. this.test()
  16. }
  17. this.count += 1
  18. }
  19. }
  20. test() {
  21. Promise.resolve().then(() => {
  22. for (let i = 0; i < 1000; i += 1) {
  23. cc.log(1)
  24. }
  25. })
  26. cc.log("test-function")
  27. }
  28. ******

执行结果为:
3.png
可以看到,1000次输出被卡在第1帧中了。