Generator函数用function*声明,返回迭代器对象,首次调用next()才执行到第一个yield;yield暂停执行,next(value)将value传给上一个yield表达式,返回{value, done}对象。

JavaScript 生成器(Generator)本身不直接处理异步,但它提供了一种暂停/恢复执行的能力,配合 Promise 和手动调用 next(),能构建出类似同步写法的异步流程。现代开发中,它已被 async/await 大幅取代,但理解它有助于掌握控制流演进逻辑。
Generator 函数怎么定义和启动?
生成器函数用 function* 声明,返回一个迭代器对象,不是立即执行函数体,而是等待 next() 调用才运行到第一个 yield。
-
yield是暂停点,每次next()都会执行到下一个yield或return - 首次
next()传参无效(因为还没进入函数体),后续next(value)的value会成为上一个yield表达式的返回值 - 返回对象格式固定:
{ value: ..., done: true/false }
function* count() {
console.log('start');
yield 1;
console.log('after first yield');
yield 2;
return 'done';
}
const it = count();
it.next(); // { value: 1, done: false }
it.next(); // 'after first yield' → { value: 2, done: false }
it.next(); // { value: 'done', done: true }
为什么 Generator 能“简化”异步?关键在 yield 暂停 + 手动 resume
核心思路是:把异步操作包装成 Promise,yield 出去;外部捕获这个 Promise,等它 resolve 后再用 next(result) 把结果送回生成器内部——就像“把回调塞回了同步位置”。
- 不能直接
yield fetch(...)然后自动等待,必须由执行器(runner)驱动 - 常见错误:忘了调用
next(),或没处理 Promise reject,导致流程卡死 - 典型执行器逻辑:检查
yield出来的是否为 Promise →.then(res => it.next(res))→ 递归驱动
function* apiFlow() {
const user = yield fetch('/user');
const posts = yield fetch(`/posts?uid=${user.id}`);
return { user, posts };
}
// 简易 runner(仅示意,不处理 error)
function run(gen) {
const it = gen();
function next(val) {
const { value, done } = it.next(val);
if (done) return value;
return value.then(res => next(res));
}
next();
}
Generator 和 async/await 的实际差异在哪?
二者语义相似,但底层机制和使用成本差别明显:
立即学习“Java免费学习笔记(深入)”;
-
async函数返回Promise,天然可await、可.then();Generator返回迭代器,必须配执行器才能跑通异步流 -
await可以直接等任意 thenable,yield出的东西需由执行器约定如何处理(比如只处理 Promise) - V8 对
async有深度优化,Generator在协程调度上开销更大,且无法被引擎自动识别为异步入口 - 调试体验差:Generator 的堆栈是断裂的,每次
next()都是新调用帧;async保留更连贯的 await 链
现在还该用 Generator 做异步控制吗?
绝大多数场景不该。除非你在维护老项目(如早期 co 库代码)、写底层运行时、或刻意做教学演示。浏览器和 Node.js 全面支持 async/await 后,手写执行器既易错又无必要。真正值得花时间的是理解 yield 如何暴露执行权——这和 React 的 useTransition、Web Workers 的协作式调度本质相通。









