相信很多有Unity经验的程序在使用CocosCreator时都在问, cc有协程吗?对一直使用js/ts的程序来説,不就是await/async吗?
其实两者不一様,协程的核心理念是把一个同歩运算变成异歩运算,过程中把函数分阶段执行, 减轻在某些同歩运算高消耗CPU导致表现上出现卡住情况从而改善用户体验,与线程不同的是,协程也是在主线程中运行, 所以不需要考虑线程安全性问题。
用Unity的定义是:
以下我会分享一下我使用Cocos协程的经验,记住协程函数一定要加*号在前
案例1. 分帧实例prefab:
相信有很多人在为了改善卡顿现像, 把实例prefab改为分帧处理(比如每帧3-5个prefab), 通常都是在update函数中, 进行处理,但若果在协程中, 处理十分优雅。
*_createPrefabObj(createPreFrame:number,maxCount:number){
for(let i = 0; i < maxCount;++i){
const n = cc.instantiate(this.prefab);
this.node.addChild(n);
if(i > 0 && i%createPreFrame == 0){
//下一帧继续
yield;
}
}
}
start(){
//其中3代表对应createPreFrame,10代表对应maxCount
Corotuine.instance.start(this,this._createPrefabObj,3,10);
}
案例2. 为label赋值后,需要取得label的尺寸进行业务处理 + 字符流输出效果
一般来说,label赋值后可以调用_forceUpdateRender直接取得Label尺寸,但这样做其实加大了一帧的处理时间,很多时候可以会用scheduleOnce或者setTimeout定时器等待1~N帧,再取得label尺寸,但在协程中可以十分优雅处理
*_labelSpeak(str:string){
this.label.string = "";
const arrStr = Array.from(str);
for(let i = 0 ; i < arrStr.length;++i){
this.label.string += arrStr[i];
//这里使用等待两帧,若果只待一帧 ,直接yield; 即可
yield Coroutine.createWaitForFrame(2);
this.lable.setPosition(new cc.Vec2(this.label.node.width,0));
}
}
onLoad(){
//这里示范用字符串调用
Coroutine.instance.start(this,'_labelSpeak','hello world');
}
案例3. 奇怪的需求,要求一个流程中处理一下,等待几秒,再处理一下再等待几秒。
有时候了为满足策划在表现上的需求,总会有一些要连续使用定时器的情况,大量的scheduleOnce+回调,在协程中可以优雅处理
*_animeEffect(){
this.node.x += 10;
//等待两秒
yield Coroutine.createWaitForSecond(2);
this.node.y += 10;
//等待5秒
yield Coroutine.createWaitForSecond(5);
}
start(){
Coroutine.instance.start(this,this._animeEffect);
}
案例4 将一个同步处理封装成异步
*_asyncProc(callback){
for(let i = 0 ; i < 100;++i){
yield:
}
callback(100);
}
packFunc(){
return new Promise((resolve,reject)=>{
Coroutine.instance.start(this,"_asyncProc",resolve);
});
}
start(){
const v = await packFunc();
}
商店地址
引擎 | 路径 | Demo版本 |
---|---|---|
3.x | Coroutine3x/assets/scripts/librarys/Coroutine.ts | 3.7.1 |
2.x | Coroutine2x/assets/Script/librarys/Coroutine.ts | 2.4.6 |