Generator 中 yield Promise 不会自动等待,仅暂停并返回 Promise 对象;控制权交由调用方,通过 next() 或 throw() 手动恢复执行,实现可观察、可干预的异步流程。

Generator 函数中主动 yield 一个 pending Promise,本身不会等待它完成,而是立刻暂停函数执行、交出控制权;真正的控制权流转,发生在外部调用方如何响应这个 Promise 的 settle(fulfill/reject)并决定何时恢复生成器。
yield 不是 await:Promise 被“抛出”,而非被“拦截”
当你写 yield fetch('/api'),生成器只做一件事:求值 fetch('/api')(触发请求),得到一个 pending Promise,然后立即暂停,把这个 Promise 作为 value 返回给调用方。生成器内部不监听、不等待、不处理这个 Promise —— 它已“交棒”出去。
- 生成器此时处于
suspended状态,所有局部变量、执行位置都完整保留 - 返回的是类似
{ value: pendingPromise, done: false }的对象 - 后续逻辑(比如用响应数据继续执行)完全依赖外部是否以及如何调用
next(result)
控制权真正由调用方接管:next() 是恢复开关
调用方拿到 pending Promise 后,必须主动监听其状态,并在适当时机调用 it.next(result) 或 it.throw(error) 来把控制权交还给生成器。
-
成功路径:Promise resolve 后,调用
it.next(resolvedValue),该值会成为上一个yield表达式的返回值(如const data = yield fetch(...)中的data) -
失败路径:Promise reject 后,调用
it.throw(err),错误会沿生成器内部的try/catch向上冒泡 - 调用
next()的时机完全自由:可立即、可延时、可加重试逻辑、可结合用户交互判断是否继续
常见执行器如何桥接这一流转
手动管理 next() 容易出错,因此常用执行器封装这一模式:
-
co 库:自动检测
yield出的 Promise,.then()后调用next(),.catch()后调用throw() -
redux-saga:
yield call(apiFn)返回的是纯描述对象(effect),saga middleware 解释后发起真实请求,结果就绪再恢复生成器 -
手写 runner:通常用递归
function run(it, result?) { const { value, done } = it.next(result); if (done) return value; if (value instanceof Promise) value.then(run.bind(null, it)).catch(err => it.throw(err)); }
关键在于“通信协议”而非“自动执行”
yield 在这里本质是一个通信信号:生成器说“我需要这个异步结果”,调用方负责供给并反馈。这种解耦让状态流转变得可观察、可干预、可测试。
- 你可以插入日志、校验、条件跳过(比如检查缓存命中就不调用
next()) - 可以批量并发多个
yield,再统一收集结果后恢复(需自定义调度) - 甚至可以用
yield返回非 Promise 值(如字符串、函数),执行器按约定处理,实现更广义的状态驱动

















