Generator是手动协程,async/await是自动协程:Generator依赖外部执行器(如co库)手动调用next()驱动yield暂停/恢复,而async/await由引擎内置状态机自动调度,无需第三方库,语法更简洁、错误处理更直观、与Promise生态天然融合。

Generator是手动协程,async/await是自动协程
Generator函数(function*)本身不处理异步,它只是提供“暂停/恢复”能力:遇到yield就停住,靠外部调用next()继续。要让它跑通异步流程,必须额外写一个执行器(比如著名的co库),把yield出来的Promise接住、等它完成,再把结果传回next(value)。这个过程是手动驱动的,开发者得理解迭代器协议和状态流转。
而async/await把这套模式封装进语言本身:你写await fetch(...),引擎自动把它编译成类似yield fetch(...),再内置一个不可见的执行器持续调用.next(),直到整个函数结束。不需要手动迭代,也不依赖第三方库。
从Promise+Generator组合到语法糖落地
早期实践是把Promise和Generator硬凑在一起:
- 用
yield抛出Promise,比如yield fetch('/api') - 执行器监听Promise resolve,再调
gen.next(result) - 出错时调
gen.throw(err)让Generator内部try/catch捕获
这种写法解决了回调地狱,但仍有明显负担:每次都要配执行器;错误传播路径绕;多个yield需要递归或循环驱动。ECMAScript标准组意识到这是通用模式,于是直接把它升级为原生语法——async函数隐式返回Promise,await自动等待并解包,try/catch天然覆盖异步异常。
立即学习“Java免费学习笔记(深入)”;
关键演进点:自动状态机取代手动调度
Generator的执行分阶段:每遇到一个yield就是一个断点,共n+1次next()调用(n个yield + 1个return)。手动执行器要自己维护这个状态流转;而async/await由JavaScript引擎在编译期生成状态机,运行时自动推进。例如:
async function f() { await a(); await b(); return c(); } 等价于一个三状态机:
— 初始态:执行a(),挂起等待
— 中间态:收到a结果,执行b(),再次挂起
— 终止态:收到b结果,执行c()并resolve返回值
为什么async/await成了事实标准
它不是推翻Generator,而是站在其肩上做了三件事:
- 去掉显式
function*和yield,用async/await降低认知门槛 - 把Promise作为唯一异步载体,统一错误处理语义(
reject→catch) - 与现有语法无缝融合:可
await任何thenable,支持for await...of遍历异步迭代器
如今所有主流环境都原生支持async/await,而手动维护Generator执行器已基本退出生产实践。Generator仍在特定场景有用(如惰性序列、状态管理中间件),但异步流程主干,已由async/await稳稳承接。


















