generator 函数中 yield 的核心价值是显式暴露执行权交接点,它使函数状态流转从隐式线性推进变为外部手动触发的离散步骤,支持可控暂停、双向数据传递与异步状态机构建。

Generator 函数的 yield 关键字,核心价值不在于“返回一个值”,而在于**显式暴露执行权的交接点**——它把函数内部的状态流转,从隐式、自动的线性推进,变成由外部调用方(如 runner、co 库或自定义调度器)手动触发的离散步骤。这种可控暂停,正是它支撑手动异步状态流转的底层根基。
yield 是一个“可中断的执行锚点”
普通函数一旦开始执行,就直奔 return 或结束;而 yield 所在位置,是代码中唯一能被 next() 精确命中并停住的地方。每一次 yield 都像在代码里钉下一个“断点桩”:
- 函数体不是被整体调用,而是被“分段加载”:只有调用
next()时,才从上一个 yield 处恢复,运行到下一个 yield 或 return; - yield 行本身不执行后续逻辑,它只负责交出当前 value 并挂起上下文(包括变量、作用域链、执行位置);
- 这意味着:你可以在 yield 后面写异步操作(比如发起 fetch),但真正“等待结果”的动作,由外部决定何时调用 next() 来继续——这正是手动控制状态流转的起点。
yield 支持双向数据传递,让状态可反馈
yield 不仅能向外输出(value),还能向内接收(next(value) 传入的参数成为上一个 yield 的返回值)。这个能力让“下一步怎么走”可以动态响应上一步的结果:
- 例如:
const data = yield api.get('/user'),当外部拿到请求结果后,调用it.next(response),response 就直接赋给了 data; - 错误也能被注入:
it.throw(err)会把错误抛进生成器内部 try/catch,实现失败路径的手动接管; - 这就把“异步成功/失败/重试/跳过”等状态决策,从回调嵌套里解放出来,交由外部调度逻辑统一判断。
yield 让异步逻辑回归线性书写,但不牺牲控制权
你可以把一段含多个异步步骤的流程,写成看似同步的代码:
function* fetchUserFlow() {const token = yield login();
const user = yield getUser(token);
const profile = yield getProfile(user.id);
return { user, profile };
}
这段代码没有 await,也没有 .then,但它天然表达了依赖顺序。关键在于:每一行的执行时机完全由你掌控——你可以等网络响应后再 next,也可以加延时、做校验、甚至根据用户操作跳过某步。它不是“自动异步”,而是“可调度的异步骨架”。
yield 是 async/await 的语义原型,但更透明
async/await 实际上是对 Generator + 自动调度器(如 Promise 驱动的 co)的语法糖封装。yield 的价值正在于它的“不隐藏”:
- 它不自动 resolve Promise,迫使你显式处理 Promise 的生命周期(例如用
yield Promise.resolve(...)或包装执行器); - 它不强制绑定 Promise,支持任意异步模型(事件、定时器、WebSocket 消息、甚至人工点击)作为恢复条件;
- 调试时你能清楚看到每一步的暂停点和传入值,而不是被 await 的黑盒行为掩盖。
换句话说,yield 提供的是“异步状态机”的最小可行接口:暂停、传参、恢复、报错——所有高级异步抽象,都建立在这个四元组之上。










