JS | 一文搞懂ES6的生成器函数(Generator Function)
目录

![]()
生成器函数(Generator Function)是 JavaScript(ES6+)、Python 等语言中一种特殊的函数,核心作用是 分步生成数据、按需产出结果,而非一次性返回所有值。它的核心特点是「暂停执行、惰性求值」,能有效节省内存(尤其处理大数据集时),并支持迭代器协议(可通过 for...of 循环遍历)。
一、核心本质
普通函数调用后会 一次性执行完毕并返回结果(或 undefined),执行过程中无法暂停;生成器函数调用后 不会立即执行,而是返回一个「生成器对象(Generator Object)」—— 这个对象既是「迭代器」(有 next() 方法),也是「可迭代对象」(可被 for...of 遍历)。
只有通过调用生成器对象的 next() 方法,函数才会执行,直到遇到 yield 关键字暂停(返回一个包含 value 和 done 属性的对象),将 yield 后的值作为「当前结果」返回;再次调用 next(),函数从暂停处继续执行,直到下一个 yield 或函数结束。
二、语法特征(以 JavaScript 为例)
- 函数声明时加 * 标记(function*);
- 函数体内用 yield 关键字「产出」数据(每次 yield 对应一次结果);
- 调用时直接写 fn(),返回生成器对象(而非执行函数体)。
- 生成器函数返回的迭代器对象符合迭代器协议,包含next()、return()和throw()方法。
基础示例:
// 定义生成器函数
function* numberGenerator() {
yield 1; // 第一次调用 next() 产出 1,暂停
yield 2; // 第二次调用 next() 产出 2,暂停
yield 3; // 第三次调用 next() 产出 3,暂停
return "结束"; // 第四次调用 next(),返回 return 值,函数终止
}
// 调用生成器函数:返回生成器对象(函数体未执行)
const generator = numberGenerator();
// 调用 next() 触发执行,返回 { value: 产出值, done: 是否结束 }
console.log(generator.next()); // { value: 1, done: false }
console.log(generator.next()); // { value: 2, done: false }
console.log(generator.next()); // { value: 3, done: false }
console.log(generator.next()); // { value: "结束", done: true }
console.log(generator.next()); // { value: undefined, done: true }(后续调用均返回此结果)
三、关键特性
1. 惰性求值(按需生成)
生成器不会一次性计算所有结果,只有当调用 next() 时才会生成下一个值。适合处理 大数据集、无限序列,仅在需要时计算值(如斐波那契数列),避免一次性加载所有数据导致内存溢出:
// 生成无限递增的整数序列(不会占用大量内存)
function* infiniteGenerator() {
let i = 0;
while (true) {
yield i++;
}
}
const infinite = infiniteGenerator();
console.log(infinite.next().value); // 0
console.log(infinite.next().value); // 1
console.log(infinite.next().value); // 2
// 按需获取,永远不会耗尽(但不会占满内存)
2. next() 可传参(给上一个 yield 赋值)
next(arg) 的参数会作为「上一个 yield 表达式的返回值」,实现「双向通信」(生成器产出值,调用方法传递参数):
function* talkGenerator() {
// 第一次 next() 产出问题,暂停;name 接收下一次 next() 的参数
const name = yield "你好,请问你叫什么?";
// 第二次 next() 产出问候,暂停
yield `你好,${name}!`;
}
const talk = talkGenerator();
// { value: "你好,请问你叫什么?", done: false }
console.log(talk.next().value);
// { value: "你好,小明!", done: false }
console.log(talk.next("小明").value);
3. 可被 for...of 遍历
生成器对象是可迭代对象,for...of 会自动调用 next(),直到 done: true(会忽略 return 的值):
function* fruitGenerator() {
yield "苹果";
yield "香蕉";
yield "橙子";
return "遍历结束"; // for...of 会忽略此值
}
// 遍历生成器
for (const fruit of fruitGenerator()) {
console.log(fruit); // 输出:苹果、香蕉、橙子(无 "遍历结束")
}
4. yield* 委托遍历
yield* 可以将遍历权委托给另一个生成器(或可迭代对象,如数组),简化嵌套生成器的调用:
function* subGenerator() {
yield 3;
yield 4;
}
function* mainGenerator() {
yield 1;
yield 2;
yield* subGenerator(); // 委托给 subGenerator,相当于 yield 3、yield 4
yield 5;
}
for (const num of mainGenerator()) {
console.log(num); // 输出:1、2、3、4、5
}
四、Python中的生成器函数(补充)
Python 中生成器函数的逻辑与 JS 一致,语法差异:
- 无需 function*,直接用 def 定义;
- 用 yield 产出值,调用后返回生成器对象;
- 同样支持 next() 调用和 for...of(Python 中是 for...in)遍历。
Python 示例:
def number_generator():
yield 1
yield 2
yield 3
return "结束"
# 调用生成器函数,返回生成器对象
gen = number_generator()
print(next(gen)) # 1
print(next(gen)) # 2
print(next(gen)) # 3
# print(next(gen)) # 抛出 StopIteration 异常,异常值为 "结束"
# for...in 遍历(自动处理 StopIteration)
for num in number_generator():
print(num) # 1、2、3(忽略 return 值)
五、应用场景
1、处理大数据集 / 文件:逐行读取大文件、分批处理数据库查询结果(避免一次性加载所有数据);
2、生成无限序列:斐波那契数列、自增 ID 生成器等;
// 生成斐波那契数列:
function* fibonacci() {
let [a, b] = [0, 1];
while (true) {
yield a;
[a, b] = [b, a + b];
}
}
const fib = fibonacci();
console.log(fib.next().value); // 0
console.log(fib.next().value); // 1
3、异步流程控制(JS 早期):在 async/await 普及前,生成器常与 co 库配合实现异步代码同步化(现在已被 async/await 替代,但原理相通);
// 异步流程控制生成器可用于简化异步代码,结合yield暂停特性,实现类似同步的异步操作写法。
function* fetchUser() {
const response = yield fetch('https://api.example.com/user');
const data = yield response.json();
return data;
}
const generator = fetchUser();
const promise = generator.next().value;
promise.then(response => {
return generator.next(response).value;
}).then(data => {
console.log(generator.next(data).value);
});
4、迭代器封装:简化自定义可迭代对象的实现(无需手动写 Symbol.iterator 方法)。
5、实现状态机:生成器天然适合实现状态机逻辑,每个yield代表一个状态节点
function* trafficLight() {
while (true) {
yield 'red';
yield 'yellow';
yield 'green';
}
}
const light = trafficLight();
light.next().value; // 'red'
light.next().value; // 'yellow'
六、生成器函数总结
生成器函数使用 function* 语法定义,它是一种特殊的函数,执行时不会立即运行其内部代码,而是返回一个生成器对象(该对象同时是一个迭代器)。通过调用这个生成器对象的 next() 方法,函数会执行到遇到下一个 yield 关键字时暂停,并返回一个包含 value 和 done 属性的对象。这使得生成器函数能够暂停和恢复执行,为异步编程和自定义迭代逻辑提供了强大的工具。
生成器函数的核心是「暂停 - 恢复」的执行机制和「惰性求值」的特性:
- 普通函数:一次执行,返回所有结果;
- 生成器函数:分步执行,按需返回结果,节省内存且支持灵活的双向通信。
- 它是处理「需要分步生成数据」场景的高效工具,也是理解迭代器、异步编程(如 async/await)的重要基础。
注意事项
- 执行顺序:生成器函数在首次调用next()时才开始执行,而非声明时。
- 错误处理:可通过generator.throw()向生成器内部抛出错误,需在函数体内用try/catch捕获。
- 资源清理:若提前终止生成器,应调用generator.return()释放资源。
- 兼容性:旧版浏览器需通过Babel等工具转译。
优化建议
- 避免频繁创建:对性能敏感场景,复用生成器对象而非重复创建。
- 结合for...of:遍历生成器时使用for...of语法更简洁:
for (const value of fibonacci()) {
if (value > 100) break;
console.log(value);
}
- 与Promise配合:使用库如co或异步生成器(ES2018)进一步简化异步代码:
async function* asyncGenerator() {
yield await Promise.resolve(1);
}
参考资料:
ES6的迭代器(Iterator)和生成器(Generator) | MDN:function* | ES6生成器函数详解
![]()
更多推荐



所有评论(0)