新闻中心

如何使用 Generator 函数和 yield 关键字实现一个复杂的状态机?

2025-10-08
浏览次数:
返回列表
状态机是一种由状态、转移条件和动作组成的计算模型,任意时刻仅处于一个状态,如登录流程可用其建模。Generator函数通过yield暂停执行,适合用同步写法控制状态流转,如实现包含“未登录”“登录中”“已登录”“锁定”的认证状态机,每次调用next()传入事件触发状态切换,并返回当前状态,结合yield特性可清晰表达复杂状态逻辑,支持注入副作用,适用于工作流与UI导航等场景。

如何使用 generator 函数和 yield 关键字实现一个复杂的状态机?

在 J*aScript 中,利用 Generator 函数和 yield 关键字可以非常优雅地实现一个复杂的状态机。Generator 能暂停和恢复执行的特性,天然适合表达状态流转。

什么是状态机?

状态机是一种计算模型,由一组状态、转移条件和动作组成。任意时刻只能处于一个状态,根据输入触发状态之间的切换。比如自动售货机、登录流程、游戏 AI 都可用状态机建模。

Generator 的核心优势

Generator 函数通过 *function 定义,使用 yield 暂停执行,每次调用 next() 才继续。这让我们可以用同步写法表达异步或分步逻辑,非常适合控制状态流转。

特点包括:

  • 函数执行可中断,保留上下文
  • 通过 next(value) 向内部传值
  • yield 表达式的返回值是 next() 传入的参数

实现一个带事件驱动的状态机

下面是一个模拟用户认证流程的状态机:包含“未登录”、“登录中”、“已登录”、“锁定”四种状态。

function* authStateMachine() {
  let state = 'idle';
  let attempts = 0;
  const maxAttempts = 3;

  while (true) {
    const { type, password } = yield state;

    if (state === 'idle') {
      if (type === 'LOGIN') {
        if (password === 'secret') {
          state = 'authenticated';
        } else {
          attempts++;
          if (attempts >= maxAttempts) {
            state = 'locked';
          } else {
            state = 'pending';
          }
        }
      }
    } else if (state === 'pending') {
      if (type === 'LOGIN') {
        if (password === 'secret') {
          state = 'authenticated';
        } else {
          attempts++;
          if (attempts >= maxAttempts) {
            state = 'locked';
          }
        }
      }
    } else if (state === 'authenticated') {
      if (type === 'LOGOUT') {
        state = 'idle';
        attempts = 0;
      }
    } else if (state === 'locked') {
      if (type === 'RESET') {
        state = 'idle';
        attempts = 0;
      }
    }
  }
}

如何使用这个状态机

创建实例并驱动状态变化:

小爱开放平台 小爱开放平台

小米旗下小爱开放平台

小爱开放平台 291 查看详情 小爱开放平台
const machine = authStateMachine();
console.log(machine.next().value); // 输出: idle

console.log(machine.next({ type: 'LOGIN', password: 'wrong' }).value); // pending
console.log(machine.next({ type: 'LOGIN', password: 'wrong' }).value); // pending
console.log(machine.next({ type: 'LOGIN', password: 'wrong' }).value); // locked
console.log(machine.next({ type: 'RESET' }).value);                   // idle
console.log(machine.next({ type: 'LOGIN', password: 'secret' }).value); // authenticated

每一步调用 next(input) 相当于发送一个事件,状态机根据当前状态和输入决定下一个状态,并通过 yield state 返回当前状态。

扩展思路:支持异步操作与副作用

可以在状态转移时插入副作用,比如记录日志、发请求等:

if (state === 'idle' && type === 'LOGIN') {
  console.log('正在验证...');
  // 模拟异步验证
  await new Promise(resolve => setTimeout(resolve, 100));
  if (password === 'secret') {
    state = 'authenticated';
  }
}

注意:如果加入 async/await,就无法再用普通 Generator 控制。此时可结合 Thunk 或 Promise 包装器,或者改用 async generatorasync function*)配合 for await...of 处理。

总结:Generator + yield 提供了一种线性、清晰的方式来编写复杂状态逻辑。相比一堆 if/else 或状态表,它更易读、易维护,尤其适合工作流、协议解析、UI 导航等场景。

基本上就这些。

以上就是如何使用 Generator 函数和 yield 关键字实现一个复杂的状态机?的详细内容,更多请关注其它相关文章!


# 是一个  # 阳江seo首页网站  # 银川建设网站哪家好  # 品牌边界营销推广方案  # 珠海360seo哪家好  # 南城服装网站优化哪里好  # 汕头网站建设制作  # 网站推广外包营销服务  # 重庆谷歌seo找谁做  # 成都的网络营销推广公司  # 青岛网站建设推广免费咨询  # 可以用  # 有哪些  # javascript  # 如何实现  # 如何用  # 可以使用  # 工作流  # 是一种  # 小爱  # 如何使用  # ai  # mac  # go  # java  # word 


相关栏目: 【 科技资讯46185 】 【 网络学院92790


相关推荐: Yandex搜索引擎一键访问入口_俄罗斯Yandex官网免登录  CSS布局中意外空白:解决padding-top导致的顶部间距问题  KFC早餐时段怎么领特惠代码_KFC早餐订餐优惠代码获取与使用说明  优化 Jest 模拟:强制未实现函数抛出错误以提升测试效率  如何使用Go和Martini动态服务解码后的图片  飞书妙记怎样用语音转文字速记_飞书妙记用语音转文字速记【速记方法】  Shopware订单对象中获取产品自定义字段的正确方法  将HTML Canvas内容转换为可上传的图像文件(File对象)  抖音隐秘迷城小游戏入口_ 抖音冒险解谜小游戏秒玩  LINUX怎么设置定时任务_LINUX crontab配置教程  Golang如何优化内存分配与垃圾回收_Golang内存管理与GC优化实践  Yandex官网免登录入口_俄罗斯Yandex搜索引擎一键访问  c++如何使用Meson构建系统_c++比CMake更快的构建工具  优化Django表单:提交验证失败后保留用户输入  PostgreSQL海量数据高效导入策略:Python与Django实践指南  Golang如何实现微服务鉴权与权限控制_Golang微服务鉴权与权限管理实践  高德地图公交到站提醒失败如何解决 高德提醒权限设置  《铁拳8》黑皮辣妹新实机:元气满满的18岁少女!  Highcharts 雷达图径向轴标签定制指南:利用多Y轴实现数值标注  微博网页版主页入口 微博官方网站免登录访问  反效果?《战地6》免费试玩开启后玩家数不升反降  J*a中实现Go语言select通道多路复用机制  Go语言中JSON数据解码与字段访问指南  Excel函数批量查找替换超快方法_Excel用REPLACE和FIND函数秒级替换  机器学习中对数变换预测结果的反向还原  深入理解J*a编译器的兼容性选项:从-source到--release  基于动态规划的房屋花卉种植最小成本算法详解  EMS快递官网app_中国邮政速递物流手机客户端  Eclipse怎么运行工程_Eclipse工程运行配置说明  Golang如何实现状态模式管理对象状态_Golang State模式实现技巧  win11专注助手在哪 Win11免打扰模式设置与自动化规则【指南】  在WordPress中通过REST API获取BasicAuth保护的远程文章  腾讯视频怎么举报不良内容_腾讯视频内容举报流程与违规信息处理方法  苹果手机如何防止被恶意App追踪  正确连接J*aScript到HTML实现可点击图片与自定义事件处理  红果短剧网页版官网入口 官方最新网址发布  KFC游戏互动怎么赢取优惠券_KFC线上游戏活动参与与优惠代码赢取教程  抓大鹅解压小游戏 抓大鹅摸鱼解压入口  学习通在线学习平台 学习通网页版直接进入课程中心  在命令行怎么运行html项目_命令行运行html项目方法【教程】  俄罗斯方块最新版入口 俄罗斯方块在线玩官网入口  在J*a中如何开发简易博客标签推荐系统_博客标签推荐项目实战解析  C++如何操作注册表_Windows平台下C++读写注册表的API函数详解  AO3官方可用镜像 Archive of Our Own网页版最新入口  优化大型XML文件解析:基于Python流式处理的内存高效方案  曝R星经典之作开发图 设计简陋但信息密集!  html网页设计源代码怎么运行_运行html网页设计源代码步骤【指南】  怎么在html里运行vbs脚本_html中运行vbs脚本方法【教程】  深入理解Go语言中的指针类型:以*string为例  msn官网入口地址手机版 msn官方网站手机最新链接 

搜索