生成器函数是用function声明的可暂停/恢复执行的特殊函数,返回Generator实例,本质为协程雏形;yield实现双向通信与惰性计算,yield委托迭代;适用于无限序列、手动异步控制及状态机建模。

生成器函数是能暂停/恢复执行的特殊函数
JavaScript 生成器不是普通函数,它用 function* 声明,返回一个可迭代对象(Generator 实例),本质是**协程雏形**——执行中途能停住、保存全部上下文(变量、作用域、执行位置),等你调用 next() 再继续。这不是语法糖,而是运行时机制级支持。
常见错误现象:直接调用 myGenerator() 不会执行函数体,只返回一个 Generator 对象;试图用 for...of 遍历但忘了它内部必须有 yield,结果循环不触发任何产出。
- 必须用
next()触发执行,首次调用才开始运行到第一个yield - 每次
next()返回{ value: ..., done: false/true },不是裸值 - 生成器一旦
done: true,后续next()永远返回{ value: undefined, done: true }
yield 是暂停点,也是双向通信接口
yield 不是 return 的替代品,它是“暂停并交出控制权”的指令。关键在于:它既能向外产出值,也能向内接收值——下一次 next(value) 传入的参数,会成为当前 yield 表达式的返回值。
function* counter() {
let n = 0;
while (true) {
n = yield n; // ← 这里:产出 n,暂停;恢复时,传入的值赋给 n
}
}
const gen = counter();
gen.next(); // { value: 0, done: false }
gen.next(10); // { value: 10, done: false } → n 变成 10
gen.next(100); // { value: 100, done: false }
- 首次
next()传参会被忽略(没地方接) -
yield后面的表达式只在暂停时求值,实现惰性计算 - 若想让生成器提前结束,可用
gen.return(value)或抛错gen.throw(err)
yield* 是委托迭代,不是调用子函数
yield* 的核心作用是“把当前生成器的控制权透明转交给另一个可迭代对象”,包括其他 Generator、Array、String、Map 等。它不是执行完子生成器再继续,而是像管道一样串联迭代流。
立即学习“Java免费学习笔记(深入)”;
技术上面应用了三层结构,AJAX框架,URL重写等基础的开发。并用了动软的代码生成器及数据访问类,加进了一些自己用到的小功能,算是整理了一些自己的操作类。系统设计上面说不出用什么模式,大体设计是后台分两级分类,设置好一级之后,再设置二级并选择栏目类型,如内容,列表,上传文件,新窗口等。这样就可以生成无限多个二级分类,也就是网站栏目。对于扩展性来说,如果有新的需求可以直接加一个栏目类型并新加功能操作
function* numbers() {
yield 1;
yield* [2, 3]; // ← 委托给数组,自动展开
yield 4;
}
[...numbers()]; // [1, 2, 3, 4]
-
yield* iter中的iter必须是可迭代对象(有[Symbol.iterator]) - 子迭代器的
throw()和return()会透传回父生成器,错误传播是连通的 - 别写成
yield* someGenerator()而不赋值——那只是创建并丢弃一个新生成器实例,没意义
实际用在哪?别硬套,先看这三类刚需场景
生成器不是炫技工具。真正值得用的地方很具体:
- 无限序列或大数据流:比如斐波那契、日志轮转、分页请求缓存——按需生成,不占内存
-
手动控制异步流程:配合
co库或手写 runner,把Promise链变成同步写法(虽然后来被async/await覆盖,但理解它有助于读懂老项目) -
状态机建模:游戏 AI、表单步骤、协议解析——每个
yield是一个稳定状态,next()是外部触发的事件
容易被忽略的一点:生成器函数本身不能 await,但可以用 async function* 创建异步迭代器(ES2018+),这时 yield 产出的是 Promise,需搭配 for await...of 使用——这是两个不同层级的特性,混用前务必确认目标环境支持。










