阮老师的介绍:Generator 函数有多种理解角度。语法上,首先可以把它理解成,Generator 函数是一个状态机,封装了多个内部状态。
红宝书(第四版):生成器是 ECMAScript 6 新增的一个极为灵活的结构,拥有在一个函数块内暂停和恢复代码执行的能力。这种新能力具有深远的影响,比如,使用生成器可以自定义迭代器和实现协程。
大白话:比较自由的异步函数;
生成器的定义可以通过 * 来实现。
function *firstGenerator(){
/* 可以写在任意位置,如:
function* firstGenrator,function * firstGenrator,function *firstGenrator*/
//你想写的内容
console.log('Hello Generator')
}
//使用
let use_firstGenerator = firstGenerator();
use_firstGenerator.next();//必须调用.next方法才行。
有点像迭代器,可以用 next 来进入下一步的动作。
其中,可以通过 yield 来设置 步骤 。
function* helloWorldGenerator() {
yield 'hello';
yield 'world';
return 'ending';
}
var hw = helloWorldGenerator();
hw.next()// { value: 'hello', done: false }
hw.next()// { value: 'world', done: false }
hw.next()// { value: 'ending', done: true }
hw.next()// { value: undefined, done: true }
每次 .next() 会进入下个yield关键字的前面,比如第一个 .next() 会进入 hello 前面,除了可以作为函数的中间返回语句使用,yield 关键字还可以作为函数的中间参数使用。上一次让生成器函数暂停的 yield 关键字会接收到传给next()方法的第一个值。这里有个地方不好理解:第一次调用 next()传入的值不会被使用,因为这一次调用是为了开始执行生成器函数。
中间有一些标准,注意规范不在此列出,想看可以细看阮老师的ES6文档 .
function* helloWorldGenerator(one) {
console.log(one);
let two = yield 'hello';
console.log(two);
let three =yield 'world';
console.log(three);
return 'ending';
}
var hw = helloWorldGenerator(1);
hw.next(2)//1 { value: 'hello', done: false }
hw.next(3)//2 { value: 'world', done: false }
hw.next(4)//3 { value: 'ending', done: true }
hw.next()//4 { value: undefined, done: true }
next中的参数将作为上一次迭代的返回值(上次执行后,yield的返回值)
使用 yield* 实现递归算法: yield* 最有用的地方是实现递归操作(第四版红宝石),此时生成器可以产生自身。看下面的例子:
function* nTimes(n) {
if (n > 0) {
yield* nTimes(n - 1);
yield n - 1;
}
}
for (const x of nTimes(3)) {
console.log(x);
}
// 0
// 1
// 2
在这个例子中,每个生成器首先都会从新创建的生成器对象产出每个值,然后再产出一个整数。结
果就是生成器函数会递归地减少计数器值,并实例化另一个生成器对象。从最顶层来看,这就相当于创
建一个可迭代对象并返回递增的整数。
与迭代器类似,生成器也支持“可关闭”的概念。一个实现 Iterator 接口的对象一定有 next()方法,还有一个可选的 return()方法用于提前终止迭代器。生成器对象除了有这两个方法,还有第三个方法:throw()。