JavaScript中Generator本身不是协程,但能模拟其核心行为:通过function*定义、yield暂停、next()恢复、双向通信,配合调度器实现协作式并发;async/await是其语法升级,提供自动调度与更优错误处理。

JavaScript 中的 Generator 本身不是协程,但它能模拟协程的核心行为:函数可暂停、可恢复、可传递数据,配合手动或自动调度器,就能实现轻量级并发处理。
Generator 是协程的“骨架”,不是完整协程
Generator 函数用 function* 定义,执行后返回一个迭代器对象。调用 next() 会运行到下一个 yield 处暂停,并返回 { value, done }。这和协程的“挂起/恢复”高度相似,但关键区别在于:
- Generator 不具备自动调度能力——它不会自己切出、也不会抢占式切换;
- 没有内置的“并发上下文”——多个 Generator 共存时,谁执行、何时执行、如何通信,全靠外部控制;
- 不共享栈或状态——每次
next()调用是同步的,无法真正并行(除非结合 Promise + 微任务)。
所以,Generator 是协程思想的“可编程接口”,而非运行时协程。
用 yield + Promise 实现协作式异步并发
最常见也最实用的方式是让 Generator yield Promise,再由执行器(runner)等待 Promise settle 后,把结果传回继续执行。这实现了“异步操作挂起、完成后再恢复”的协程语义。
立即学习“Java免费学习笔记(深入)”;
例如:
在 Java 中初始化和管理阿里云 SDK客户端。包括单例模式、线程安全、endpoint 与 region 配置、VPC 终端节点、同步与异步等。
function* fetchData() {
const user = yield fetch('/api/user');
const posts = yield fetch(`/api/posts?uid=${user.id}`);
return { user, posts };
}
<p>// 简易 runner(不依赖库)
function run(gen) {
const it = gen();
function next(val) {
const { value, done } = it.next(val);
if (done) return value;
// 假设 value 是 Promise
return value.then(res => next(res));
}
return next();
}</p>这个 run 就是一个单线程协作式调度器:每个 yield 表示一次“让出控制权”,等异步完成再“恢复执行”。它不阻塞主线程,也不需要多线程支持,天然契合 JS 事件循环。
用 async/await 替代 yield —— 语言层面的协程进化
ES2017 引入 async/await 后,上述模式被更简洁、更健壮的方式取代:
async function fetchData() {
const user = await fetch('/api/user');
const posts = await fetch(`/api/posts?uid=${user.id}`);
return { user, posts };
}
async 函数底层仍基于 Promise 和状态机(V8 中甚至复用了 Generator 的编译逻辑),但它隐藏了手动调度细节,支持 try/catch、for await、Promise.all 并发组合等,实际就是 JS 对协程的官方支持方案。Generator + runner 的写法现在主要用于学习、定制调度(如游戏帧更新、状态机)、或与旧生态兼容。
进阶:用 Generator 构建有限状态机或协作任务调度器
当需要精细控制多个任务的执行节奏(比如动画帧调度、多步骤表单流程、游戏 AI 行为树),Generator 非常适合表达“分步、可中断、可重入”的逻辑:
- 每个
yield可代表一个逻辑阶段(如“播放动画 → 等待 200ms → 检查条件 → 决定分支”); - 外部调度器可根据时间、事件或条件决定是否调用
next(),甚至throw()注入错误或中断; - 多个 Generator 实例可共存,由统一调度器轮询或事件驱动,实现伪并发(cooperative multitasking)。
这类用法在 Redux-Saga、Vue 3 的 useAsyncState(部分实现)、或自研流程引擎中仍有价值——它们把 Generator 当作“可暂停的程序脚本”,而非单纯异步语法糖。

















