Generator函数本身不是异步原语,不被事件循环直接调度,其执行由调用方通过next()控制;需配合Promise和执行器(如co库或async/await)实现异步协作,本质是yield暂停与微任务驱动的结合。

事件循环本身不直接调度 Generator 函数,Generator 也不属于宏任务或微任务;它的执行完全由调用方控制,但可以被设计为配合事件循环实现异步协作——关键在于手动或借助工具(如 co 库、async/await)将 yield 暂停点与 Promise 链衔接。
Generator 本质是可暂停的函数,不是异步原语
Generator 函数通过 yield 主动交出控制权,返回一个迭代器对象;它不会自动等待异步操作完成,也不会被事件循环识别为待执行任务。是否继续执行,取决于外部是否调用 next() 或 send()。
- 定义 Generator 后,仅返回迭代器,函数体不执行
- 首次调用
next()才开始执行,遇到yield暂停,并返回{ value, done } - 后续每次
next()都从暂停处恢复,直到函数结束
Generator + Promise 实现异步协作
要让 Generator 真正“等待”异步结果(比如 fetch、定时器),需把 yield 后的值约定为 Promise。外部执行器(runner)捕获该 Promise,等其 resolve 后再调用 next(value) 推进 Generator。
-
yield fetch('/api/user')返回 Promise,但 Generator 不会自动 await 它 - 执行器需监听该 Promise 的
then,在回调中调用it.next(result) - 常见模式:
function* gen() { const data = yield Promise.resolve(1); return data + 1; },配合 runner 才能产出 2
async/await 是 Generator + Promise 的语法糖封装
ES2017 的 async/await 在底层复用了 Generator 和 Promise 的协作逻辑:V8 引擎将 async 函数编译为状态机,内部用 yield 模拟暂停点,用微任务(Promise.then)驱动下一步 —— 这正是事件循环介入 Generator 的典型方式。
-
await表达式等价于yield后接 Promise,且自动处理 resolve/reject - 引擎确保
await后的 Promise resolve 后,以微任务形式触发后续代码(即进入 microtask 队列) - 因此
async函数体内的同步代码仍走主线程,await 切换则依赖事件循环调度微任务
实际协作流程示例
假设有一个 Generator 异步流程:
function* fetchData() {
const a = yield fetch('/api/a'); // 返回 Promise
const b = yield fetch('/api/b');
return [a, b];
}一个简易 runner 如下:
- 调用
next()启动,得到{ value: promiseA, done: false } -
promiseA.then(res => it.next(res))→ 触发第二次next,传入响应结果 - 第二次
next执行到yield fetch('/api/b'),重复上述过程 - 最终
done: true,返回结果;整个过程依赖事件循环处理每个 Promise 的微任务回调


















