生成器函数(Generator Function)是 JavaScript 中一种特殊的函数,它可以在执行过程中暂停并在之后恢复执行。生成器函数使用 function*
语法定义,并且内部使用 yield
表达式来暂停函数执行并返回一个值。每次调用生成器函数返回的迭代器的 next
方法时,生成器函数会从上次暂停的地方继续执行,直到遇到下一个 yield
表达式或函数结束。
生成器函数的定义和用法
定义生成器函数
生成器函数使用 function*
关键字定义:
function* generatorFunction() {yield 'First output';yield 'Second output';return 'Finished';
}
调用生成器函数
调用生成器函数会返回一个迭代器对象,该对象具有 next
方法:
const gen = generatorFunction();
迭代生成器函数
使用 next
方法迭代生成器函数,每次调用 next
方法,生成器函数会执行到下一个 yield
表达式,并返回一个对象 { value: any, done: boolean }
:
console.log(gen.next()); // { value: 'First output', done: false }
console.log(gen.next()); // { value: 'Second output', done: false }
console.log(gen.next()); // { value: 'Finished', done: true }
console.log(gen.next()); // { value: undefined, done: true }
生成器函数的特性
-
暂停和恢复执行:
生成器函数在遇到yield
表达式时会暂停执行,并返回yield
后的值。函数的状态会被保存下来,下一次调用next
方法时会从暂停的地方继续执行。 -
双向通信:
可以通过next
方法传递参数给生成器函数,生成器函数内部可以接收这个参数并进行处理。 -
实现迭代器协议:
生成器函数返回的迭代器对象遵循迭代器协议,可以用于for...of
循环和其他需要迭代器的地方。
示例
简单生成器函数
function* simpleGenerator() {yield 1;yield 2;yield 3;
}const gen = simpleGenerator();console.log(gen.next()); // { value: 1, done: false }
console.log(gen.next()); // { value: 2, done: false }
console.log(gen.next()); // { value: 3, done: false }
console.log(gen.next()); // { value: undefined, done: true }
双向通信的生成器函数
function* counter() {let count = 0;while (true) {const increment = yield count;if (increment != null) {count += increment;} else {count++;}}
}const countGenerator = counter();console.log(countGenerator.next().value); // 0
console.log(countGenerator.next(2).value); // 2
console.log(countGenerator.next(3).value); // 5
console.log(countGenerator.next().value); // 6
用于异步操作的生成器函数
生成器函数可以与 Promise
结合使用,处理异步操作,使异步代码更接近同步风格。
function fetchData(url) {return new Promise((resolve) => {setTimeout(() => {resolve(`Data from ${url}`);}, 1000);});
}function* asyncTaskQueue() {const data1 = yield fetchData('https://api.example.com/endpoint1');console.log(data1);const data2 = yield fetchData('https://api.example.com/endpoint2');console.log(data2);const data3 = yield fetchData('https://api.example.com/endpoint3');console.log(data3);
}function run(generator) {const iterator = generator();function handle(result) {if (result.done) return;result.value.then(data => {handle(iterator.next(data));});}handle(iterator.next());
}run(asyncTaskQueue);
生成器函数的优势
- 灵活性:生成器函数可以暂停和恢复,适用于复杂的控制流逻辑。
- 双向通信:可以通过
yield
和next
实现双向数据传递。 - 内存友好:在处理大型数据集时,可以逐个生成数据项,而不是一次性加载所有数据。
- 异步编程:与
Promise
结合,可以更容易地处理异步操作。
生成器函数为 JavaScript 提供了一种强大而灵活的方式来处理迭代、异步操作和复杂的控制流。理解并善用生成器函数可以大大提升代码的可读性和可维护性。