参考文档

生成器

生成器函数在执行时能暂停,后面又能从暂停处继续执行。

JavaScript 中的生成器和 Promise 结合使用是进行异步编程的强大工具,因为它们减轻了诸如回调地狱和控制反转的问题。然而对于这些问题可以通过 async 函数实现更简单的坚决方案

调用一个生成器函数并不会马上执行它的主体,而是返回一个这个生成器对象。当迭代器 next() 方法被调用时,生成器函数的主体会执行到首个 yield 表达式处,该表达式制定了要从迭代器返回的值,或使用 yield* 委托给其他生成器函数。next() 方法返回一个包含 valuedone 属性的对象。调用带参数的 next() 方法将恢复生成器函数的执行,用 next() 中的参数替换暂停执行的 yield 表达式。

生成器中的 return 语句执行时意味着生成器结束(done 属性设置为 true)。如果返回一个值,它将被设置为生成器返回的 value 属性。与 return 语句非常类似,在生成器内部抛出的错误将使生成器结束,除非在生成器主体中完成 catch。一个生成器结束时,后续的 next() 调用将不会执行该生成器的任何代码,只会返回一个这样的对象 {value: undefined, done: true}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
// 简单示例
function* idMaker() {
let index = 0;
while (true) {
yield index++;
}
}

const gen = idMaker();

console.log(gen.next().value); // 0
console.log(gen.next().value); // 1
console.log(gen.next().value); // 2
console.log(gen.next().value); // 3
// …
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
// yield* 示例
function* anotherGenerator(i) {
yield i + 1;
yield i + 2;
yield i + 3;
}

function* generator(i) {
yield i;
yield* anotherGenerator(i);
yield i + 10;
}

const gen = generator(10);

console.log(gen.next().value); // 10
console.log(gen.next().value); // 11
console.log(gen.next().value); // 12
console.log(gen.next().value); // 13
console.log(gen.next().value); // 20
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
// 带参数的 next
function* logGenerator() {
console.log(0);
console.log(1, yield);
console.log(2, yield);
console.log(3, yield);
}

const gen = logGenerator();

// the first call of next executes from the start of the function
// until the first yield statement
gen.next(); // 0
gen.next('pretzel'); // 1 pretzel
gen.next('california'); // 2 california
gen.next('mayonnaise'); // 3 mayonnaise
1
2
3
4
5
6
7
8
9
10
11
// 返回值
function* yieldAndReturn() {
yield "Y";
return "R";
yield "unreachable";
}

const gen = yieldAndReturn();
console.log(gen.next()); // { value: "Y", done: false }
console.log(gen.next()); // { value: "R", done: true }
console.log(gen.next()); // { value: undefined, done: true }
1
2
3
4
5
6
7
8
9
10
11
12
13
// 作为对象属性的生成器
const someObj = {
*generator () {
yield 'a';
yield 'b';
}
}

const gen = someObj.generator()

console.log(gen.next()); // { value: 'a', done: false }
console.log(gen.next()); // { value: 'b', done: false }
console.log(gen.next()); // { value: undefined, done: true }
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
// 作为对象方法的生成器
class Foo {
*generator() {
yield 1;
yield 2;
yield 3;
}
}

const f = new Foo();
const gen = f.generator();

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 }
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
// 作为计算属性的生成器
class Foo {
*[Symbol.iterator]() {
yield 1;
yield 2;
}
}

const SomeObj = {
*[Symbol.iterator]() {
yield 'a';
yield 'b';
}
}

console.log(Array.from(new Foo)); // [ 1, 2 ]
console.log(Array.from(SomeObj)); // [ 'a', 'b' ]
1
2
3
// Generators are not constructable
function* f() {}
const obj = new f; // throws "TypeError: f is not a constructor