Generator 是执行流控制器,通过 yield 结构化指令定义步骤与暂停点,由事件总线拦截、注入和广播状态,实现可中断、可追溯、可干预的调试化流程控制。

Generator 本身不是语法糖,而是 JavaScript 的原生协程机制;async/await 才是 Generator + Promise 的语法糖。所谓“用 Generator 配合事件总线打造受控按步流调试总线组件”,本质是利用 Generator 的暂停/恢复能力 + 事件总线的解耦通信,构建一个可中断、可注入、可追溯的执行流控制系统。它不依赖框架,也不靠黑魔法,关键在三点:状态可控、事件可溯、步骤可干预。
明确 Generator 的角色定位:执行流控制器,不是业务逻辑容器
Generator 在这里不负责处理具体业务(如发请求、改 DOM),只定义“该走哪一步、何时停、停在哪”。每一步 yield 必须返回结构化指令,而非原始值:
- 统一返回 { type: 'STEP_START', id: 'fetch-user', payload: { userId: 123 } } 这类带语义的 action 对象
- 禁止 yield 字符串、数字或裸对象——无法被事件总线识别和拦截
- 所有异步操作(如 API 调用)必须封装为纯函数(loader),Generator 只 yield 指令,由外部监听器响应并触发
事件总线作为中间调度层:拦截 yield、注入结果、广播状态
事件总线(例如一个轻量 EventEmitter 或 mitt 实例)承担三件事:监听 Generator 步骤、注入外部数据、广播当前状态。不直接调用 next(),而是封装一层可控执行器:
- 监听 'step:request' 事件,收到 { type: 'FETCH_USER', id: 'step-1' } 后,执行对应 loader 并 emit 'step:resolve'
- 当 Generator yield 出指令后,执行器暂停,并 emit 'debug:paused',附带 stepId、timestamp、当前上下文快照
- 支持外部通过 bus.emit('step:resume', { stepId, result }) 注入数据,执行器再调用 gen.next(result)
调试能力来自可插拔的拦截点与状态快照
高鲁棒性不体现在“不出错”,而在于“出错可定位、可回退、可重放”。每个 yield 点都应视为一个可观测锚点:
- 每次 next() 前,自动记录 call stack 片段 + 参数快照 + 时间戳,存入内存缓冲区(不落盘,避免 IO 拖慢)
- 支持按 stepId 跳过(bus.emit('step:skip', 'step-3'))、重试(bus.emit('step:retry', 'step-2'))、回滚(bus.emit('step:rollback', 2))
- yield 指令中携带 meta: { editable: true, timeout: 8000 },供调试面板动态修改参数或超时阈值
避免常见陷阱:不共享状态、不隐式跳转、不手动管理 done
Generator 实例是一次性的,且不可重入。鲁棒性崩塌常源于以下误用:
- 多个调试操作共用同一个 generator 实例 → 每次启动新流程必须 new Generator(),不可复用
- 在事件回调里直接调用 next() 而不检查 done → 执行器必须封装 guard:if (!result.done) bus.emit('step:next')
- yield 后试图修改外部变量影响后续逻辑 → 所有中间状态必须显式传入 next(value),Generator 内部不读写闭包外 mutable 数据

















