学习Generator

解宏扬
2023-12-01

Generator()

阮老师的介绍: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()。

  1. return()方法会强制生成器进入关闭状态。提供给 return()方法的值,就是终止迭代器对象的值。
  2. throw()方法会在暂停的时候将一个提供的错误注入到生成器对象中。如果错误未被处理,生成器就会关闭 。
 类似资料: