javascript生成器函数是ES6引入的一种特殊函数,它和普通函数的执行逻辑有明显区别,核心特点是可以分段执行、暂停和恢复,而实现这一特性的关键就是yield关键字。生成器函数执行后不会直接运行函数体内容,而是返回一个迭代器对象,通过迭代器的方法可以控制函数体的执行节奏。

生成器函数的基础定义
生成器函数的声明方式和普通函数不同,需要在function关键字后面加一个星号*,函数内部可以使用yield关键字来定义暂停点。和普通函数调用后立即执行完所有逻辑不同,生成器函数调用后仅返回迭代器,不会执行函数体内的代码。
下面是一个最简单的生成器函数示例:
// 声明生成器函数,function后带*
function* simpleGenerator() {
console.log('执行第一段逻辑');
// 第一个暂停点
yield 1;
console.log('执行第二段逻辑');
// 第二个暂停点
yield 2;
console.log('执行第三段逻辑');
return 3;
}
// 调用生成器函数,返回迭代器对象
const iterator = simpleGenerator();
console.log(iterator); // 输出生成器迭代器对象
yield暂停执行的机制
yield是生成器函数的核心关键字,它的作用是暂停生成器函数的执行,同时将后面的值返回给外部,等待下一次恢复执行。每次暂停后,需要调用迭代器的next方法才能让生成器函数从暂停的位置继续执行,直到遇到下一个yield或者函数结束。
next方法的执行逻辑
迭代器的next方法会返回一个对象,包含两个属性:value和done。value是本次yield后面跟着的表达式的值,done表示生成器函数是否已经执行完毕,执行完毕时done为true,否则为false。
我们基于上面的simpleGenerator来演示执行过程:
const iterator = simpleGenerator();
// 第一次调用next,执行到第一个yield暂停
const result1 = iterator.next();
console.log(result1); // { value: 1, done: false }
// 此时控制台输出:执行第一段逻辑
// 第二次调用next,从第一个yield之后继续执行,到第二个yield暂停
const result2 = iterator.next();
console.log(result2); // { value: 2, done: false }
// 此时控制台输出:执行第二段逻辑
// 第三次调用next,从第二个yield之后继续执行,直到return结束
const result3 = iterator.next();
console.log(result3); // { value: 3, done: true }
// 此时控制台输出:执行第三段逻辑
// 之后再调用next,done始终为true,value为undefined
const result4 = iterator.next();
console.log(result4); // { value: undefined, done: true }
yield表达式的返回值
yield本身也是一个表达式,它的返回值由下一次调用next方法时传入的参数决定。如果在调用next时传入了参数,这个参数会成为上一个yield表达式的返回值。
示例代码如下:
function* paramGenerator() {
const a = yield '请输入第一个值';
console.log('接收到的第一个值:', a);
const b = yield '请输入第二个值';
console.log('接收到的第二个值:', b);
return a + b;
}
const paramIterator = paramGenerator();
// 第一次调用next,执行到第一个yield,返回'请输入第一个值'
console.log(paramIterator.next()); // { value: '请输入第一个值', done: false }
// 传入10,作为第一个yield的返回值,赋值给a,继续执行到第二个yield
console.log(paramIterator.next(10)); // { value: '请输入第二个值', done: false }
// 传入20,作为第二个yield的返回值,赋值给b,继续执行到return
console.log(paramIterator.next(20)); // { value: 30, done: true }
生成器函数的常见使用场景
按需生成数据序列
生成器函数非常适合生成无限或者大量的数据序列,不需要一次性把所有数据都存放在内存中,而是需要的时候再生成下一个,节省内存开销。
比如生成一个自然数序列:
function* naturalNumbers() {
let num = 1;
while (true) {
// 每次调用next就生成下一个自然数,不会无限循环占用内存
yield num;
num++;
}
}
const numIterator = naturalNumbers();
console.log(numIterator.next().value); // 1
console.log(numIterator.next().value); // 2
console.log(numIterator.next().value); // 3
// 可以一直调用,按需获取
简化异步流程控制
在async/await出现之前,生成器函数常被用来处理异步操作,通过yield暂停等待异步结果,避免回调嵌套的问题。虽然现在async/await更常用,但理解生成器处理异步的逻辑也有助于掌握异步编程的演进。
简单模拟异步操作的示例:
// 模拟异步请求函数
function mockAsyncRequest(url) {
return new Promise(resolve => {
setTimeout(() => {
resolve(`请求${url}的结果`);
}, 1000);
});
}
function* asyncGenerator() {
console.log('开始第一个请求');
const res1 = yield mockAsyncRequest('/api/data1');
console.log('第一个请求结果:', res1);
console.log('开始第二个请求');
const res2 = yield mockAsyncRequest('/api/data2');
console.log('第二个请求结果:', res2);
return '所有请求完成';
}
// 执行生成器处理异步
const asyncIterator = asyncGenerator();
// 处理第一个异步
asyncIterator.next().value.then(res1 => {
// 把第一个异步结果传给生成器
return asyncIterator.next(res1).value;
}).then(res2 => {
// 把第二个异步结果传给生成器
return asyncIterator.next(res2);
}).then(finalRes => {
console.log(finalRes.value); // 所有请求完成
});
注意事项
- 生成器函数内部不能使用箭头函数的形式声明,必须带function*的语法。
- yield关键字只能在生成器函数内部使用,在普通函数中使用会报错。
- 生成器函数返回的迭代器是一次性消耗的,遍历完之后无法再重新开始,如果需要重复遍历,需要重新调用生成器函数生成新的迭代器。
- 如果生成器函数内部抛出错误,迭代器的done会直接变为true,后续调用next也不会再执行函数体逻辑。
生成器函数通过yield实现执行暂停的特性,为javascript提供了更灵活的控制流能力,无论是处理数据生成还是异步逻辑,都能带来更简洁的代码写法,是值得掌握的重要特性。
javascript生成器函数yield迭代器修改时间:2026-07-19 20:51:29