Cocos Creator协程组件!你真的懂协程吗?

確實, 我判斷错了

js的协程Generators是es6的时候出来的,之前是没有的.js的异步底层是宏任务微任务,所以实现Generators也是基于这个事件循环,你把协程代码转成es5代码就可以发现它的实现原理

setTimeout(()=>{},0) 和 this.scheduleOnce(()=>{},0)是不一样的。前者只是把任务立刻放到任务队列里,当前帧的同步代码执行完立刻就执行了,不会等到引擎的下一帧。而后者是会延迟到下一帧执行的。

这个可以实现利用空闲时间完成耗时运算(平常一帧算不完)而不导致卡顿吗?

看你是想怎麽处理, 如果是 在while 或 for里, 使用yield字様就会执行到这就释放运算, 下一帧再继续, 记住函数名前加*号, 不然yield无法生效

控制在一帧时间快到的时候再停止而不是每帧跑一个yield

你这种想方法是不对的
协程的作用在于把一件事分多个帧去处理, 减少一帧的压力
比你原本你要1帧实例100个敌人, 那麽那一帧100%卡, 但是你可以分成每帧实例5个, 20帧实例完
那麽你for循还只需要 for(let i = 0 ;i < 100;++i){ if(i > 0 && i%5==0) yield };
当for执行完结后,协程就销毁了。

一帧差不多13毫秒,第一帧5毫秒渲染完了我让协程跑8毫秒,第二帧10毫秒渲染完了我让协程跑3毫秒。
这样

你协程函数里要执行多久是你自己写了甚麽代码
你可以这様 , yield是分隔线, 一个函数里可以有多个yield

function *f(){
      //第一帧内容
      let a = 0;
     for(let i= 0 ;i < 100;++i){
         a+=i;
     }
     yield //以上是第1帧运行,下面是第二帧
     let b = 0;
    for(let i= 0 ;i <10;++i){
         b+=i;
     }

    //如果有第三帧要处理的东西再加yield, 否则不写或return
}

协程每次yield的时候检测此时是否为空闲时间,是则next,否则等下一帧渲染后的空闲时间,除非卡顿严重否则只用空闲时间跑协程

问题协程怎麽知道现在是否为空闲? 空闲的定义是甚麽?unity协程有实现你想要的"空闲"时处理吗?协程是主进程里执行的, 别把协程跟线程混淆

private *_test() {

    let lastUpdate = cc.director._lastUpdate

    let checkNext = function () {

        if (performance.now() - lastUpdate > 1000 / cc.game.getFrameRate()) {

            console.log("wait for next frame")

            lastUpdate = cc.director._lastUpdate

            return false

        }

    }

    while (true) {

        if (!checkNext()) {

            yield;

        }

    }

}

Coroutine.instance.start(this, this._test);

实现了协程跑无限循环(实际应用为耗时而不需要一帧内完成的方法)而不阻塞游戏循环

我总算理解你想做啥了, 我觉得你这个还不如直接监听
cc.director.on(cc.Director.EVENT_AFTER_UPDATE, this._update, this);
this._update里处理你的一帧耗时计算

在这里要怎么实现呢?这一帧跑太久就达不到满帧率了

为啥要想满帧率呢?看一下引擎源码就知道, 全单线程, 跑完脚本update 再跑render
image
你用不用协程都不可能满帧率,一秒跌个5帧肉眼也看不出变化, 你只要清楚甚麽东西最会拖慢帧率就行。
另外你看一下CoroutineMgr的源码吧, ta也是基于监听cc.Director.EVENT_AFTER_UPDATE
你那while ture checkNext 也是每帧在跑, 根本没有减轻运算量, 当checkNext return true时还会因为while(true) 阻塞整个主线程

Coroutine2.zip (280.9 KB)
可以的话看下这个

我大致理解你这处理, 就单纯利用时间差值来决定要不要让n增加
所以想你表达是如果主update执行太久, 协程不执行,期望达到满帧率, 但引擎代码都表示了, 在update完成后才跑render函数, 而你的cc.director._lateUpdate值是在mainLoop中未跑update前在函数calculateDeltaTime里更新了, 所以你那协程时间判断只是在判断你脚本的时间, 根本没判断到render时间,所以render 高压力时, 你还是无法满帧率。当然你可以把协程改在cc.Director.EVENT_AFTER_DRAW后执行,但从我的角度来看, 搞了这一堆没有甚麽实制意义的提升