资讯专栏INFORMATION COLUMN

Generator函数在流程控制中的应用

only_do / 1828人阅读

摘要:可以利用这点做定时器的清理工作,而且可以说基本不会忘记可以将后面的变量可迭代的变量,字符串数组等中的值一个一个的返回。执行一次返回其中的一个值函数完美实现流程图代码部分其他变量下注下注阶段完成后直接清除定时器。

扯蛋

做了两年的Nodejs全栈开发,不知道为什么跑来做游戏呢(大概是厦门nodejs不好找工作吧)。用的是网易的pomelo的游戏框架。现接手了一个棋牌游戏:二十一点,不懂的规则的可以自行百度。

二十一点游戏流程图

现状

接手了平台其他相关游戏的代码,流程控制相互交错,不易理解、难以维护。(可能是刚做游戏的原因,如果你们有什么更简单的流程控制方法,欢迎分享)。我下意识的就想到了Generator函数的特性,感觉用着这里非常方便(以前一直觉得这是个异步流程控制中过度性质的方法,并且需要配合co才能自动执行,所以基本没实际用过,koa不算...)

Js Generator函数实现流程控制的优点

1、易于理解、便于开发、容易维护(看到Generator函数犹如看到了流程图)
2、开发思路清晰(每个阶段(函数)只需要关注自己的业务逻辑,完成直接下一步,而不用管下一步要做什么操作)
3、不存在会忘记清除定时器的问题

简单说下Generator的执行流程

1、Generator函数执行后会生成一个Iterator。(注意不要加new)(简单说就是个有next方法的对象,执行一次返回一个值)
2、每次next的调用,执行yield后面的语句并返回该语句执行的结果
3、每次只执行一个yield,后面的语句不会再执行、只有在执行下次next函数时才执行。(可以利用这点做定时器的清理工作,而且可以说基本不会忘记)
4、yield* 可以将后面的变量(可迭代的变量,字符串、数组等)中的值一个一个的返回。执行一次返回其中的一个值

Js Generator函数完美实现流程图代码(部分)
class EsydProcess {

    constructor(room) {
        /**
         * ...其他变量
         */
        this.flow = this.flowGenerator();
    }

    *["flowGenerator"]() {

        yield this.betStage(); // 下注
        this.betStageTimer && clearTimeout(this.betStageTimer);// 下注阶段完成后直接清除定时器。完全不用担心定时器没有被清理的情况

        yield this.assignStage(); // 分牌

        if (this.esydCard.getCardPoint(this.bankerCards[0]) === 1) {

            yield this.ensureStage(); // 保险
            this.ensureStageTimer && clearTimeout(this.ensureStageTimer);

            if (this.esydCard.getCardType(this.bankerCards) !== CardTypes.BLACK_JACK) {
                yield* this.operateStage(); // 操作
            }

        } else {
            yield* this.operateStage(); // 操作
        }

        yield this.settleStage(); // 结算
    }

    *["operateStage"]() {
        // 通知进入玩家操作阶段
        this.noticeChangeStage(esydConsts.gameStage.OPERATE_STAGE);
        let players = this.players;
        for (let uid in players) {
            let player = players[uid];

            // 操作第一副牌
            yield this.changeOperatingPlayer(player);
            player.getCurCardInfo().isStop = true;
            this.operateTimer && clearTimeout(this.operateTimer);

            if (player.isSperated) {
                // 如果有一副牌,操作第二副牌
                player.curCardsIndex = 1;
                yield this.changeOperatingPlayer(player);
                player.getCurCardInfo().isStop = true;
                this.operateTimer && clearTimeout(this.operateTimer);
            }
        }
        yield this.bankerOperate(); // 庄家操作
    }

    // 转到下个阶段
    nextStage() {
        process.nextTick(() => {
            this.flow.next();
        });
    }
    
    // 开始游戏
    start(seats) {
        /**
         * ...
         *
         */
        // 第一次next,直接进入下注阶段。整个流程走完游戏结束
        this.nextStage();
    }
    
    betStage(){
        // 进入下注阶段
        this.noticeChangeStage(esydConsts.gameStage.BET_STAGE);
        /**
         * 其他操作
         */
        this.betStageTimer = setTimeout(() => {
            this.betStageTimer = null;
            // 超时,直接进入下一步。没有下注的玩家使用默认底注
            this.nextStage();
        }, esydConsts.stageTime.BET_STAGE);
    }

    assignStage(){
        /**
         * ...
         * 分牌操作,完成直接下一步
         */
        this.nextStage();
    }

    ensureStage(){
        /**
         * ...
         * 各种操作,如通知客户端、开始超时定时器等。操作完后直接下一步就Ok了。只需要专注当前函数的功能,完成直接下一步
         */
        this.nextStage();
    }

    // 监听用户下注操作
    userBetOperateListener(uid){
    
        /**
         * ...
         * 检查是否在下注阶段,不是不能下注、记录每个玩家下注等
         */
         
        // 记录已下注的玩家
        this.betedPlayers[uid] = true;
        if (Object.keys(this.betedPlayers).length === this.seatCount) {
            // 如果所有玩家都押注完毕,
            this.nextStage();
        }
    }
    
    /**
     *  其他函数...
     */

}

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/99568.html

相关文章

  • 异步流程控制:7 行代码学会 co 模块

    摘要:而在中是迭代器生成器,被创造性的拿来做异步流程控制了。当执行的时候,并不执行函数体,而是返回一个迭代器。行代码再看看文章开头的行代码首先生成一个迭代器,然后执行一遍,得到的是一个对象,里面再执行。 广告招人:阿里巴巴招前端,在这里你可以享受大公司的福利和技术体系,也有小团队的挑战和成长空间。联系: qingguang.meiqg at alibaba-inc.com 首先请原谅我的标题...

    tinna 评论0 收藏0
  • 《Node.js设计模式》基于ES2015+的回调控制

    摘要:以下展示它是如何工作的函数使用构造函数创建一个新的对象,并立即将其返回给调用者。在传递给构造函数的函数中,我们确保传递给,这是一个特殊的回调函数。 本系列文章为《Node.js Design Patterns Second Edition》的原文翻译和读书笔记,在GitHub连载更新,同步翻译版链接。 欢迎关注我的专栏,之后的博文将在专栏同步: Encounter的掘金专栏 知乎专栏...

    LiuRhoRamen 评论0 收藏0
  • Generator开始学习Koa

    摘要:需要说明的是,每次执行完函数之后,都会返回一个对象这个返回值有两个属性和,对象通过这个返回值来告诉外界函数的执行情况。函数的返回值变成这样可以发现的值变为了,因为函数已经执行完了。在规范中,新增了两个协议可迭代协议和迭代器协议。 Koa是最近比较火的一款基于Node的web开发框架。说他是一个框架,其实他更像是一个函数库,通过某种思想(或者说某种约定),将众多的中间件联系在一起,从而提...

    doodlewind 评论0 收藏0
  • 通过ES6 Generator函数实现异步流程

    摘要:换句话说,我们很好的对代码的功能关注点进行了分离通过将使用消费值得地方函数中的逻辑和通过异步流程来获取值迭代器的方法进行了有效的分离。但是现在我们通过来管理代码的异步流程部分,我们解决了回调函数所带来的反转控制等问题。 本文翻译自 Going Async With ES6 Generators 由于个人能力知识有限,翻译过程中难免有纰漏和错误,还望指正Issue ES6 Gener...

    刘厚水 评论0 收藏0
  • 关于协程和 ES6 中的 Generator

    摘要:关于协程和中的什么是协程进程和线程众所周知,进程和线程都是一个时间段的描述,是工作时间段的描述,不过是颗粒大小不同,进程是资源分配的最小单位,线程是调度的最小单位。子程序就是协程的一种特例。 关于协程和 ES6 中的 Generator 什么是协程? 进程和线程 众所周知,进程和线程都是一个时间段的描述,是CPU工作时间段的描述,不过是颗粒大小不同,进程是 CPU 资源分配的最小单位,...

    RyanHoo 评论0 收藏0

发表评论

0条评论

only_do

|高级讲师

TA的文章

阅读更多
最新活动
阅读需要支付1元查看
<