async/await是Promise的语法糖,依托生成器函数能力实现:async标记函数并封装返回值为Promise,await暂停执行并等待异步完成后再恢复,其行为可通过“生成器+自动执行器”模拟,但现代引擎采用更高效的状态机原生实现。

async/await 本身不是生成器,但它的行为可以被模拟为“生成器 + 自动执行器”的组合。这种模拟不用于生产环境(现代引擎已原生支持),而是帮助理解其暂停、恢复、错误传递等核心机制。关键在于:用 yield 替代 await,用执行器函数接管 Promise 状态变化,并驱动生成器前进。
生成器函数作为异步流程骨架
把 async 函数体改写为生成器函数,每个 await 表达式换成 yield:
原始 async 函数:
async function fetchUser() {
const res = await fetch('/api/user');
const data = await res.json();
return data.name;
}对应生成器函数:
function* fetchUserGen() {
const res = yield fetch('/api/user'); // yield 返回 Promise,由执行器处理
const data = yield res.json(); // 同样 yield 一个 Promise
return data.name;
}这个生成器不自己处理异步,只负责定义步骤和产出 Promise,交由外部执行器调度。
执行器函数:自动调用 next 并桥接 Promise
执行器接收生成器函数,创建迭代器,然后递归调用 next(),并在 Promise 完成后传入结果或错误:
AI 舌诊面诊问诊医疗系统 + 诊疗商城系统源码是一套结合 AI 辅助诊断与商品转化的健康类程序,基于浩创云、ThinkPHP(PHP)开发,支持微信服务号与 H5 端,适合做中医舌诊面诊问答、健康建议推送以及配套诊疗商品的运营。
- 每次
gen.next(value)得到一个 { value, done } 对象 - 若
value是 Promise,则用.then()和.catch()处理 - 成功时,用
result调用下一次next(result) - 失败时,用
throw(err)将错误抛回生成器内部(可被try/catch捕获)
简化版执行器示例:
function spawn(genFn) {
return new Promise((resolve, reject) => {
const gen = genFn();
function step(nextFn, value) {
let result;
try {
result = nextFn(value);
} catch (err) {
return reject(err);
}
if (result.done) return resolve(result.value);
Promise.resolve(result.value).then(
v => step(gen.next, v),
e => step(gen.throw, e)
);
}
step(gen.next);
});
}调用方式:spawn(fetchUserGen),返回的 Promise 行为与原 async 函数一致。
关键细节:值传递、错误传播与返回值封装
真实模拟需处理三类边界情况:
-
非 Promise 值自动包装:yield 后可能是普通值(如
yield 42),执行器应统一用Promise.resolve(value)包装,保持流程一致 -
错误必须准确抛回生成器内:不能只 reject 外层 Promise,而要调用
gen.throw(err),这样生成器内的try/catch才能捕获 -
return 值需作为最终 resolve 值:当
result.done === true,result.value就是整个异步流程的返回结果,应传给外层resolve()
为什么现代引擎不依赖生成器实现?
虽然 Babel 等转译工具在旧环境中会把 async/await 编译为生成器+spawn,但 V8、SpiderMonkey 等引擎早已采用更高效的原生方案:
- 直接将 async 函数编译为状态机,每个 await 对应一个状态跳转点
- 上下文(局部变量、暂停位置)由引擎直接管理,无需生成器对象开销
- 无手动迭代器生命周期管理,避免额外内存分配和原型链查找
- 配合 PromiseHooks 和 TurboFan 优化,性能显著优于模拟实现
因此,生成器模拟是教学和兼容性手段,不是运行时真相——它揭示的是设计思想,而非执行路径。

















