JavaScript中的生成器函数

JavaScript中的生成器函数

在本文中,我们将解释JavaScript中的生成器函数。

YouTube Video

JavaScript中的生成器函数

JavaScript生成器函数是特殊函数,与普通函数不同,它们可以进行惰性执行以及暂停和恢复。通过理解生成器函数,您可以高效处理异步操作和大规模数据的顺序处理。在这里,我们将详细解释生成器函数的工作原理、如何使用它们以及实际使用案例。

什么是生成器函数?

生成器函数通过**function*(带星号的函数定义)定义,与普通函数不同,它可以在中途暂停执行,并在保持状态的情况下恢复执行。生成器函数允许"惰性执行"**并逐步返回结果,从而实现高效的内存管理和顺序处理。

语法

1function* generatorFunction() {
2    yield 'First value';
3    yield 'Second value';
4    return 'Done';
5}

这样,生成器函数可以拥有多个yield表达式,并使用yield来暂停其执行。当调用生成器函数时,函数体不会立即执行,而会返回一个生成器对象。您可以在该对象上调用next()方法,从暂停的地方恢复函数的执行。

生成器函数的基本用法

接下来,让我们看一个使用生成器函数的基本示例。

 1function* simpleGenerator() {
 2    yield 1;
 3    yield 2;
 4    yield 3;
 5}
 6
 7const gen = simpleGenerator();
 8
 9console.log(gen.next()); // { value: 1, done: false }
10console.log(gen.next()); // { value: 2, done: false }
11console.log(gen.next()); // { value: 3, done: false }
12console.log(gen.next()); // { value: undefined, done: true }

这里需要注意的一个关键点是,生成器每次通过yield返回值,只要done属性为false,就表示还有更多的值。最后一次调用next()会返回done: true,表示生成器已完成。

使用 for...of 语法

使用 for...of 可以轻松地从生成器中获取每一个 yield 的值。

 1function* simpleGenerator() {
 2    yield 1;
 3    yield 2;
 4    yield 3;
 5}
 6
 7const gen = simpleGenerator();
 8
 9for (const value of gen) {
10    console.log(value); // 1, 2, 3
11}
  • for...of 会自动对可迭代对象(包括生成器)调用 .next(),并循环直到 donetrue
  • 在循环中,value 会依次被赋值为每个 yield 的值。
  • 使用 for...of 非常简单,因为你不需要手动调用 .next()

yield关键字和暂停值

yield是一个指示生成器函数内暂停点的关键字。调用next()时,yield右边的值将被返回。此外,yield允许双向通讯。换句话说,当将一个值作为参数传递给next()方法时,该值会被发送到生成器函数中。

 1function* generatorWithYield() {
 2    const value1 = yield 'First yield';
 3    console.log('Received value:', value1);
 4    const value2 = yield 'Second yield';
 5    console.log('Received value:', value2);
 6}
 7
 8const gen = generatorWithYield();
 9
10console.log(gen.next());        // { value: 'First yield', done: false }
11console.log(gen.next('Apple')); // Received value: Apple
12                                // { value: 'Second yield', done: false }
13console.log(gen.next('Banana'));// Received value: Banana
14                                // { value: undefined, done: true }

在此示例中,调用next('Apple')会将值'Apple'发送到生成器函数,并在函数内使用。

管理生成器状态

生成器可以保持其执行状态,从而简洁地表示长循环或顺序处理。以下示例展示了一个无限生成数字的生成器。

 1function* infiniteGenerator() {
 2    let i = 0;
 3    while (true) {
 4        yield i++;
 5        if (i > 10) {
 6            break;
 7        }
 8    }
 9}
10
11const gen = infiniteGenerator();
12
13for (const value of gen) {
14    if (value === 3) break;
15    console.log(value); // 0, 1, 2
16}

这个生成器通过使用 while(true) 循环不断生成数字,可以根据需要获取值。这使得处理大型数据集更高效。

生成器函数的应用

生成器函数适用于顺序执行多个流程。例如,它们对顺序处理 API 请求或分割并处理大型文件非常有帮助。

1function* apiRequestGenerator() {
2    yield fetch('https://codesparklab.com/json/example1.json');
3    yield fetch('https://codesparklab.com/json/example2.json');
4    yield fetch('https://codesparklab.com/json/example3.json');
5}

因此,生成器可用于异步处理,对于高效的顺序数据处理非常有益。

异步生成器

ES2018 引入的异步生成器通过结合 asyncyield,允许按顺序返回异步值。这使得结合 await 能够简洁地书写异步处理。

语法

 1async function* asyncGenerator() {
 2    yield await Promise.resolve(1);
 3    yield await Promise.resolve(2);
 4    yield await Promise.resolve(3);
 5}
 6
 7const gen = asyncGenerator();
 8
 9(async () => {
10    for await (const value of gen) {
11        console.log(value); // 1, 2, 3
12    }
13})();

异步生成器可以通过 for await...of 循环按顺序获取值。这种模式在处理异步数据流时特别有用。

实际示例:使用生成器简化异步处理

生成器函数还可以用来简化异步处理的流程。例如,通过如下所示结合 yieldPromise,可以将异步操作写得像同步操作一样。

 1function* asyncFlow() {
 2    const data1 = yield fetch('https://codesparklab.com/json/example1.json');
 3    console.log(data1);
 4    const data2 = yield fetch('https://codesparklab.com/json/example2.json');
 5    console.log(data2);
 6}
 7
 8const gen = asyncFlow();
 9
10function handleAsync(generator) {
11    const next = (promise) => {
12        promise.then((result) => {
13        const { value, done } = generator.next(result);
14        if (!done) {
15            next(value);
16        }
17        });
18    };
19
20    next(generator.next().value);
21}
22
23handleAsync(gen);

此代码用生成器依次发起 API 请求并处理结果。

总结

生成器函数是 JavaScript 的强大功能之一,具备暂停和恢复函数执行的能力。这使得进行顺序处理、异步处理以及高效操作大型数据集成为可能。理解生成器是掌握 JavaScript 高级技术的重要一步。

您可以在我们的YouTube频道上使用Visual Studio Code跟随上述文章进行学习。 请也查看我们的YouTube频道。

YouTube Video