generator函数不直接处理异步,而是通过yield暂停/恢复执行,由执行器(如co、redux-saga)驱动异步流程;async/await是其语言级替代方案,更轻量直观。

Generator 函数本身不直接处理异步,它提供的是暂停与恢复执行的机制,配合 yield 和外部手动调用 next(),让开发者能以同步风格组织异步逻辑。真正实现“控制异步流”的,是 Generator 与执行器(如 co、redux-saga 或手写的 runner)协同工作的结果。
Generator 的暂停/恢复本质
Generator 函数返回一个迭代器对象,每次调用 next() 时:
- 函数体从上次暂停位置(
yield表达式后)继续执行; - 遇到下一个
yield就再次暂停,并把右侧表达式的值作为{ value: ..., done: false }返回; - 若执行到函数末尾或
return,则返回done: true。
关键点在于:yield 后的表达式不会自动求值——它只是被“挂起”,是否执行、何时执行、如何处理其结果,完全由调用方(即执行器)决定。
如何用 yield “交出”异步操作权
Generator 内部可以 yield 任意值,比如 Promise、Thunk 函数、甚至自定义效果描述对象。常见模式有:
-
yield Promise:表示“这里等一个异步结果”,执行器需监听该 Promise 的
resolve/reject,再用next(value)或throw(error)恢复 Generator; -
yield Thunk(fn):传入一个接收
(callback)的函数,执行器调用它并传入符合 Node.js 风格的(err, data) => {...}回调,再根据结果恢复; - yield { type: 'API_CALL', payload: ... }:在状态管理场景(如 redux-saga),yield 的不是真实副作用,而是纯描述对象,由中间件解释并触发真实异步行为。
也就是说:yield 是一个通信协议,Generator 告诉执行器“我需要这个东西”,执行器负责供给并反馈结果。
执行器(Runner)才是异步流的调度核心
没有执行器,Generator 只是暂停的函数,无法自动推进。一个极简的 Promise 执行器示例如下:
function run(gen) {
const g = gen();
function next(data) {
const { value, done } = g.next(data);
if (done) return value;
return Promise.resolve(value).then(next);
}
next();
}
它做了三件事:
- 启动 Generator,拿到迭代器;
- 调用
next()获取第一个yield值(通常是个 Promise); - 用
Promise.then链式驱动后续next(),把 resolve 结果传回 Generator,形成“等待 → 恢复 → 再等待”的循环。
这就是“异步流程被 Generator 控制”的真相:Generator 定义了步骤顺序和依赖关系,执行器负责按序触发、错误传播、结果注入。
为什么后来被 async/await 取代?
Generator + 执行器的方案虽灵活,但有明显短板:
- 必须额外引入执行器库(如
co),或自己维护 runner; - 语法略重,每个异步点都要写
yield,且不能直接await在普通函数中; - 错误处理需统一靠
try/catch或执行器的throw机制,不够直观; - Generator 函数本身不能
await,也不能直接return await promise,语义受限。
async/await 本质是语言层面对“暂停-恢复-错误传播”这一模式的原生支持,无需迭代器、无需手动 next(),更轻量、更易读、更符合直觉。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











