跳到主要内容

Generator 生成器

生成器函数

生成器函数是 JavaScript 中一种特殊类型的函数,用于生成一系列值。生成器函数通过 function* 语法定义,使用 yield 关键字来暂停和恢复函数的执行。

基本概念

  • 生成器函数 (generator)
    生成器函数用于生成一系列值,可以在执行过程中暂停和恢复。

  • 迭代器对象 (iterator)
    生成器函数执行后返回一个迭代器对象,该对象符合迭代协议,可以通过调用其 next() 方法逐步获取值。

  • 产出值 (yield)
    yield 关键字用于在生成器函数内部产出一个值,并暂停函数的执行,直到下一次调用 next()

定义生成器函数

function* myGenerator() {
yield '第一步';
yield '第二步';
yield '第三步';
}

使用生成器函数

function* generator() {
yield '来小亮';
yield '给大家整个活';
yield '后空翻';
yield '杀马特团长你给我等着';
}

const iterator = generator();

let result;

result = iterator.next();
console.log(result); // { value: '来小亮', done: false }

result = iterator.next();
console.log(result); // { value: '给大家整个活', done: false }

result = iterator.next();
console.log(result); // { value: '后空翻', done: false }

result = iterator.next();
console.log(result); // { value: '杀马特团长你给我等着', done: false }

result = iterator.next();
console.log(result); // { value: undefined, done: true }

在上述代码中,generator 函数每次调用 next() 方法时,都会产出一个新的值,并返回一个对象,其中包含 valuedone 两个属性。done 表示生成器是否已经完成所有的产出。

生成器函数的实现

为了更好地理解生成器的工作原理,下面是一个简单的生成器函数的实现:

function generator(arr) {
let nextIdx = 0;
return {
next: function () {
return nextIdx < arr.length ? { value: arr[nextIdx++], done: false } : { value: undefined, done: true };
},
};
}

const myGen = generator(['苹果', '香蕉', '橘子']);

console.log(myGen.next()); // { value: '苹果', done: false }
console.log(myGen.next()); // { value: '香蕉', done: false }
console.log(myGen.next()); // { value: '橘子', done: false }
console.log(myGen.next()); // { value: undefined, done: true }

这个简单的 generator 函数接受一个数组,并返回一个具有 next 方法的迭代器对象。每次调用 next() 方法时,都会返回数组中的下一个元素,直到所有元素被遍历完毕。

生成器与 co 实现 async/await

async/await 出现之前,生成器与 co 库常被用来处理异步操作,使异步代码看起来更像同步代码。

const co = require('co');

function* myAsyncGenerator() {
const data1 = yield fetchData1();
const data2 = yield fetchData2(data1);
return data2;
}

co(myAsyncGenerator)
.then((result) => {
console.log(result);
})
.catch((err) => {
console.error(err);
});

在这个例子中,generator 函数通过 yield 关键字暂停执行,等待异步操作完成。co 库负责处理这些暂停点,并在异步操作完成后恢复生成器的执行。这样,异步代码的执行流程更为清晰和可读。

相比之下,async/await 提供了更为简洁和直接的语法,隐藏了底层的生成器和 co 的实现细节,使得编写和维护异步代码更加方便。

总结

  • 生成器函数通过 function*yield 关键字,实现了函数的暂停与恢复。
  • 迭代器对象通过调用 next() 方法,逐步获取生成器产出的值。
  • async/await 出现之前,生成器与 co 库被广泛用于处理异步操作,使异步代码更具可读性。
  • async/await 作为语法糖,简化了生成器和 co 处理异步操作的复杂性。

通过理解生成器函数的原理和使用方法,可以更深入地掌握 JavaScript 中的异步编程模式,为编写高效、可维护的代码打下坚实的基础。