async/await与生成器不能直接混用,因语法和执行机制互斥;需通过runner函数或co库桥接,使yield值被自动await,实现协程式异步流程。

在 JavaScript 中,async/await 和生成器(function*)是两套不同的异步机制,**不能直接混用**:你无法在一个 async 函数中用 yield,也不能在普通生成器函数中直接用 await。这是因为:
生成器函数(function*)本身不支持 await —— 它的执行由外部控制(如手动调用 next()),没有内置的 Promise 暂停/恢复逻辑;async 函数是语法糖,底层基于 Promise,不支持 yield —— 使用 yield 会报语法错误。
想“交替使用 yield 与 await”,实际要做的不是混合语法,而是桥接两者
常见做法是:写一个生成器函数(含 yield),再用一个“运行器(runner)”函数来遍历它,并对每个 yield 出的值做判断 —— 如果是 Promise,就 await 它;如果是普通值或可迭代对象,按需处理。这样就实现了“在生成器逻辑中穿插异步等待”的效果。
例如:
立即学习“Java免费学习笔记(深入)”;
function* myFlow() {
console.log('step 1');
yield Promise.resolve('hello'); // ← 这个会被 runner await
<p>console.log('step 2');
yield fetch('/api/data').then(r => r.json()); // ← 也会被 await</p><p>console.log('step 3');
yield 'done'; // ← 普通值,直接返回
}</p><p>// 简单 runner:自动处理 Promise 并继续 next()
function run(gen) {
const g = gen();
function next(val) {
const { value, done } = g.next(val);
if (done) return value;
return Promise.resolve(value).then(next);
}
return next();
}</p><p>run(myFlow); // 自动按序执行、await 每个 yield 出的 Promise</p><div class="aritcle_card flexRow">
<div class="artcardd flexRow">
<a class="aritcle_card_img" href="/xiazai/skill9040" title="JavaStoryDevelop"><img
src="https://img.php.cn/upload/skill/000/000/081/179238966962420.jpg" alt="JavaStoryDevelop" ></a>
<div class="aritcle_card_info flexColumn">
<a href="/xiazai/skill9040" title="JavaStoryDevelop">JavaStoryDevelop</a>
<p>你接手一个需求时,是不是经常这样:"改一个小字段 → 结果把不相关的代码也改了"、"需求说得很模糊 → 做着做着发现跑偏了"、"数据库加个字段 → 上线才发现漏了数据兼容"、"做了个新功能 → 一个月后自己都忘了当时怎么设计的"、"写到一半被中断 → 再回来不知道从哪继续";这个 Skill 就是专门解决这些问题的。 它会自动探测你的项目环境(JDK、Spring Boot、ORM、数据库、前端框架),记在</p>
</div>
<a href="/xiazai/skill9040" title="JavaStoryDevelop" class="aritcle_card_btn flexRow flexcenter"><b></b><span>下载</span> </a>
</div>
</div>更实用的方案:用 co 库或手写协程式 runner
历史上 co(TJ Holowaychuk 开发)就是为解决这个问题而生的:它把生成器当作协程,自动 await 所有 yield 出的 Promise、数组、对象等。
- 安装:
npm install co - 用法:
co(function* () { yield fetch(...); yield delay(1000); }) - 现代替代:由于
async/await已成标准,co已不推荐新项目使用,但理解其原理仍有价值
注意:不要试图在 async 函数里写 yield
以下代码会报错:
async function bad() {
yield 'no'; // ❌ SyntaxError: Unexpected reserved word
await fetch('/x');
}
同理,下面也不合法:
function* goodButNoAwait() {
yield 'ok';
await fetch('/x'); // ❌ SyntaxError: await is only valid in async functions
}
现代推荐:用 async/await + 循环/递归代替生成器流程
除非你在写框架、测试工具或需要精确控制暂停/恢复(比如状态机、游戏帧调度),否则优先用 async/await 配合 for、while 或递归实现分步逻辑:
- 用
for await...of处理异步可迭代对象(如 ReadableStream) - 用
await链式调用多个 API,配合if/switch控制分支 - 需要“暂停-恢复”语义时,可封装成返回
Promise的函数,由调用方决定何时await
本质上,yield 和 await 都是暂停执行的机制,但设计目标不同:前者面向协作式控制流(generator),后者面向异步资源等待(Promise)。它们的“交替使用”不是语法层面的共存,而是通过运行器模式在语义层面桥接。

















