<p>Generator 通过 function* 和 yield 实现协作式状态机,将状态切换映射为函数执行流的暂停/恢复,语义清晰、逻辑扁平;每个 yield 是状态出口,next() 驱动流转,输入即事件、返回即响应,天然保持局部变量,适合单流程事件驱动场景。</p>

Generator 通过 function* 和 yield 提供了原生的协作式挂起与恢复能力,让手写状态机不再需要手动维护状态变量、条件跳转或回调嵌套——它把“状态切换”自然映射为“函数执行流的暂停/继续”,语义清晰、逻辑扁平。
用 yield 把每个状态变成可中断的执行点
每个 yield 就是一个状态出口:函数执行到此处暂停,交出控制权;下次调用 next() 时从中断处恢复,并可接收新输入(通过 next(value) 传入)。这正好对应状态机中“当前状态处理输入 → 输出动作 → 转移到下一状态”的核心循环。
- 不需要显式
switch(state) { ... }或一堆if-else判断 - 状态转移逻辑内联在代码顺序中,读起来像同步流程
- 局部变量天然保留在函数作用域内,无需额外保存上下文
一个带输入驱动的状态机示例
比如实现一个简单的登录流程状态机(idle → pending → success/fail):
function* loginStateMachine() {
let user, token;
<p>// idle 状态
const action = yield { type: 'IDLE', canLogin: true };
if (action.type !== 'LOGIN_REQUEST') return;</p><p>// pending 状态
yield { type: 'PENDING' };
try {
user = yield { type: 'API_CALL', endpoint: '/login', data: action.payload };
token = user.token;
// success 状态
yield { type: 'SUCCESS', user, token };
} catch (err) {
// fail 状态
yield { type: 'FAILURE', error: err.message };
}
}</p><p>// 使用:
const sm = loginStateMachine();
console.log(sm.next()); // { value: { type: 'IDLE', canLogin: true }, done: false }
console.log(sm.next({ type: 'LOGIN_REQUEST', payload: { u: 'a', p: 'b' } })); // PENDING
console.log(sm.next({ id: 123, token: 'abc' })); // SUCCESS
每次 yield 返回当前状态快照,next(input) 输入驱动下一步——输入即事件,返回值即状态响应,状态流转完全由执行位置隐式表达。
立即学习“Java免费学习笔记(深入)”;
配合 for...of 或封装 run 函数实现自动驱动
若状态机纯靠外部事件驱动(如 UI 点击、消息到达),可封装一个 runner 自动调用 next 并响应返回的状态:
- 用
for...of遍历 generator(适合无输入或输入固定的情况) - 更常见的是写一个
run(sm, event),内部调用sm.next(event)并根据value.type做副作用(渲染、发请求等) - 遇到异步操作(如 fetch),可用
yield Promise+ 外部await暂停,或改用async function*(需搭配for await...of)
注意边界:Generator 是单次、不可逆、非并发的
它不等于线程,也不支持多路恢复。一次 generator 实例只能被一个消费者驱动;不能从外部“跳转”到某个 yield;也不能同时 resume 多个地方。因此:
- 适合单线流程、事件序列明确的状态机(如表单向导、协议解析、游戏 AI 行为树)
- 不适合需随机跳转、多状态并行或需取消/重入的场景(此时考虑 XState 或手写状态类)
- 调试时可通过
sm.return()强制结束,或捕获throw()来注入错误


















