Samwey-----优雅封装Promise------JTLocker

不多说了先上代码吧

module com

{

    export class JTLocker implements JTITaskLocker

    {

        protected __fail:Function = null;

        protected __succeed:Function = null;

        protected __signal:Promise<any> = null;

        public lock():Promise<any>

        {

            if (this.__signal) return this.__signal; //注意,当前正使用锁时,如果没有调用release 时不能再使用lock()方法

            let locker:JTLocker = this;

            this.__signal = new Promise((resolve, reject) =>

            {

                locker.__fail = reject;

                locker.__succeed = resolve;

            })

            return this.__signal;

        }

        public release():void

        {

            this.__succeed && this.__succeed.apply(this, []);

            this.clear();

        }

        public kill():void

        {

            this.__fail && this.__fail.apply(this, []);

            this.clear();

        }

        public locked():boolean

        {

            return this.__signal != null;

        }

        public tryLock():Promise<any>

        {

            return this.locked() ? this.__signal : this.lock();

        }

        public get signal():Promise<any>

        {

            return this.__signal;

        }

        public clear():void

        {

            this.recycle();

        }

        public recycle()

        {

           this.__signal = this.__fail = this.__succeed = null;

        }

        // private static _pool:JTIPool = JTPool.instance(JTLocker);

        // public static create():JTILocker

        // {

        //     let locker:JTILocker = this._pool.get() as JTLocker;

        //     return locker;

        // }

        // public static put(locker:JTLocker):void

        // {

        //     this._pool.put(locker);

        // }

    }

}

JTILocker ---接口
module com 
{
    export interface JTILocker extends JTIPoolObject
    {
         lock(key?:any):Promise<any>

         release():void

         unlock(key?:any):void;

         kill(key?:any):void
      
         locked:boolean
     
         tryLock(key:any):Promise<any>

       
    }
}
JTITaskLocker --接口
module com 
{
    export interface JTITaskLocker extends JTILocker
    {
        signal:Promise<any>;
    }
}

来测试一下代码:

let locker:c.JTLocker = new c.JTLocker();

        let state:string = "normal  ————————  "

        async function testLocker()

        {

            for (let i:number = 0; i < 10; i++)

            {

                if (i == 3)

                {

                    console.log("locked!------- ")

                    await locker.lock(); //当i等于3时,使用锁,暂停FOR循环(注意只调用了一次await locker.lock())

                    //当释放该Locker时,for循环后的7次将会继续执行

                }

                console.log(state + "test locker: " + i)

            }

        }

        //2秒钟释放锁

        setTimeout(() =>

        {

            state = "release  ————————"
             locker.unlocker();//解锁
            locker.release();//释放锁,当调用release()时,下次使用locker.lock(),代码将重新被挂起,

        }, 2000);

        testLocker();

输出得下
[INFO] :22:16:17 >>>> normal ———————— test locker: 0
[INFO] :22:16:17 >>>> normal ———————— test locker: 1
[INFO] :22:16:17 >>>> normal ———————— test locker: 2
[INFO] :22:16:17 >>>> locked!-------
[INFO] :22:16:19 >>>> release ————————test locker: 3
[INFO] :22:16:19 >>>> release ————————test locker: 4
[INFO] :22:16:19 >>>> release ————————test locker: 5
[INFO] :22:16:19 >>>> release ————————test locker: 6
[INFO] :22:16:19 >>>> release ————————test locker: 7
[INFO] :22:16:19 >>>> release ————————test locker: 8
[INFO] :22:16:19 >>>> release ————————test locker: 9

let locker:c.JTLocker = new c.JTLocker();

    let state:string = "normal  ————————  "

    // let lock:Promise<any> = locker.lock();

    async function testLocker()
    {
        try
        {
            for (let i:number = 0; i < 10; i++)
            {
                // await lock;
                info(" before lock" + i)
                await locker.lock();
                info(state + "test locker: " + i);
            }
        }
        finally
        {
            locker.release();//等循环体结束,再释放锁
           info("the loacker already release!")
        }
    }

    //2秒钟释放锁

    setTimeout(() =>
    {
        state = "release  ————————"
        locker.unlock();//先解锁
    }, 2000);
    testLocker();

可以测试看看效果

1赞

哪些具体的需求用到这个功能会更好一些呢

主要用于异步操作,(资源加载或者网络通信方面的)让代码逻辑更加直观,异步操作同步化.

//1、传统写法

    cc.loader.loadResDir("settings/", cc.TextAsset, loadAssetCompleteNormalMethod.bind(this)); //
    function loadAssetCompleteNormalMethod(err:any, resources:any):void
    {
            //加载完成后逻辑处理,对回调函数操作需要再传回调函数,
            this.launchGame();
    }

//2、Promise-JTLocker写法

    let locker:c.JTLocker = new c.JTLocker();
    cc.loader.loadResDir("settings/", cc.TextAsset, loadAssetsCompleteUseLoaderMethod.bind(this)); //
    await locker.lock();
    this.launchGame();
    //加载完成后逻辑处理, 什么时候完成,什么时候想去做,都可以交给自己去处理。
    
    function loadAssetsCompleteUseLoaderMethod(err:any, resources:any)
    {
            locker.unlock();
            locker.release();
    }

//如果有多个异步操作同时触发,每一个操作响应的时间节点都不一致时,如果使用传统的写法就会很复杂。但是使用JTLocker就相当简单.
//网络通信也是一样的,如果再稍微封装一下,

socket.send(“data”)
await result = locker.lock();

直接就拿到响应结果。

直接把异步代码封装成promise不就好了 弄这么复杂干嘛

那代码可读性很低的…而且代码的复用性无法得到充分利用。这样设计可以适用所有异步操作。任何项目、引擎,只要是TS项目都可以复用的。加一个对象池管理一下,不是更好吗?

loadRes(){
 return new Promise((resolve,reject)=>{
   cc.loader.loadResDir("settings/", cc.TextAsset, (err:any, resources:any)=>{
       if(err) return reject(err)
        resolve(resources)
    })
 })
}
//使用一行代码
const res = await loadRes()
this.launchGame();

我觉得这么写更直观 简单

2赞

你这样也可以的,但是实际项目很多都是资源很多种类型,有些是做了加密的,
一般项目都会在你这上面再封装一层,
比如说我现在有在处理Main.ts,有一个异步操作在全局的公共类里(AsyncHandler)。

现在如何将他们两者联系起来,
让我继续在Main.ts写代码。

我向服务端发送了一个请求(协议号为10000)
现在服务端响应了我的请求,
我如何实现呢。
socket.send(10000)
locker.unlock(“收到响应”)
let result:any = await locker.lock();

不明觉厉~

感谢回答,提供了写代码的新思路,加锁后这里的代码应该不会阻塞吧

代码只在当前方法内并加上await关键字才会暂停,调用方法以外的其它方法逻辑不受影响,如果想要外层方法也阻塞,需要在外层方法也加一个await 和async 修饰符