generator函数本身不直接管理状态历史,但提供可中断/恢复的执行模型,适合封装“状态变更+快照+撤销点”流程;需手动维护backward/forward双栈,通过next()接收指令驱动状态机,yield返回当前状态供外部控制快照与回溯。

Generator 函数本身不能直接“管理状态历史”,但它能提供一种天然的、可中断/恢复的执行模型——这正是实现手动控制状态快照时机与回溯逻辑的理想底座。关键不在于 Generator 多强大,而在于你如何用它封装「状态变更 + 快照 + 撤销点」的协作流程。
用 Generator 封装状态变更生命周期
把每次有意义的状态更新(比如用户输入、表单提交、视图切换)包装成一个 yield 点,让外部控制器决定何时执行、何时暂停、是否记录快照:
- Generator 内部只做纯状态变更(如 state = {...state, ...next}),不主动保存历史
- 每次 yield 返回当前状态快照(或变更描述),由调用方决定是否存入 history 数组
- 通过 next(value) 接收外部指令(如 { type: 'UNDO' }),触发回退逻辑
手动维护双栈:forward 和 backward
Generator 不自带历史堆栈,你需要配合两个数组模拟浏览器前进/后退行为:
- backwardStack:存放已执行并快照过的状态(从初始到当前),pop() 即撤销
- forwardStack:存放被撤销但可能重做的状态,push() 进去,pop() 重做
- Generator 实例本身不保存这些栈,它们是独立变量,仅在每次 yield 后由主控逻辑同步更新
用 next() 驱动状态机,而非自动遍历
不要用 for...of 或 iterator.next() 一路跑完。应将 Generator 实例作为“状态引擎”暴露给 UI 层:
- 点击「撤销」→ 调用 engine.next({ type: 'UNDO' })
- 点击「重做」→ 调用 engine.next({ type: 'REDO' })
- 触发新操作 → engine.next({ type: 'COMMIT', payload })
- Generator 内部根据 value.type 分支处理,返回新状态或当前状态
一个极简但可运行的核心骨架
以下不是完整库,而是揭示结构本质的示意代码:
function* createStateEngine(initial) {
let state = initial;
const backwardStack = [structuredClone(initial)];
const forwardStack = [];
<p>while (true) {
const cmd = yield state;</p><pre class="brush:php;toolbar:false;">switch (cmd.type) {
case 'COMMIT':
state = { ...state, ...cmd.payload };
backwardStack.push(structuredClone(state));
forwardStack.length = 0; // 清空重做队列
break;
case 'UNDO':
if (backwardStack.length > 1) {
forwardStack.push(backwardStack.pop());
state = structuredClone(backwardStack[backwardStack.length - 1]);
}
break;
case 'REDO':
if (forwardStack.length) {
const redoState = forwardStack.pop();
backwardStack.push(redoState);
state = structuredClone(redoState);
}
break;
}} }
// 使用示例 const engine = createStateEngine({ count: 0, name: '' }); console.log(engine.next().value); // { count: 0, name: '' } console.log(engine.next({ type: 'COMMIT', payload: { count: 1 } }).value); // { count: 1, name: '' } console.log(engine.next({ type: 'UNDO' }).value); // { count: 0, name: '' }
它不依赖任何框架,没有副作用,所有状态流转可见可控。真正的“完美”不在语法炫技,而在你能否用最朴素的 yield / next / 数组栈,把每一次用户意图转化为可追溯、可干预、可重放的状态事件流。











