什么是生成器?

image.png
平时我们编写的函数,是没办法暂停的(暂停意味着可以恢复执行),只能直接终止,比如执行到return后面都不执行,或者遇到错误时等等。

生成器,是和函数结合在一起使用的,通常有一个生成器函数,它的返回值是一个生成器。

生成器函数

说明

image.png

普通函数 VS 生成器函数
image.png image.png

3、调用生成器函数时,默认给你返回一个生成器对象
image.png

4、生成器是一种特殊的迭代器,因此可以调用这个生成器的 next( ) 方法,让函数执行第一段代码(见上上图第一段代码)
image.png
每调一次next函数,就执行一段代码,因此可以做到暂停和恢复

返回值

既然说生成器是一种特殊的迭代器,因此调用next就会有返回值,而迭代器的返回值格式就是一个对象,里面有done属性和value属性

image.png image.png
最后的done是true,表示执行完了

为什么value 是undefined?因为我们没有给他规定返回值。

怎么规定返回值?只要在对应的 yield 关键字后面增加想要返回的内容即可(可以是表达式)
最后一个done:true的value,是这个函数最终return的内容
image.png image.png

传递参数

image.png
获取生成器的时候,可以传参数,传入的参数,就是生成器函数接收的参数;

执行第一段代码,此时不能传参数(传了也没用);

执行第二段代码,此时传的参数,就是第一个 yield 的返回值,如此类推。

提前结束 return (少)

image.png
如果在第二次应该调用next函数时,对生成器调用return方法,相当于在第二段代码处,插入return,第二段代码以及后面的都不执行;

如果在第 n 次应该调用next函数时,对生成器调用return方法,相当于在第 n 段代码处,插入return,第 n 段代码以及后面的都不执行;
image.png
这样就能提前结束生成器函数的调用
image.png

抛出异常 throw (少)

说明

image.png
image.png(准备第二次调用next时,调用了throw)
image.png(相当于 let a = yield value1 , a 是throw异常)
此时可以通过try catch语句捕获异常,执行catch里面的代码,然后接着执行第二段代码

image.png (甚至可以传递参数)
image.png

应用

image.png
一般可能用于,上一个返回的值,我们不满意,作个判断,抛出异常,停止函数执行

===============

使用场景

1、优化迭代器

迭代器:https://www.yuque.com/yejielin/mypn47/qv4hk9

之前迭代器有个例子,模拟实现数组的迭代器

现在可以使用生成器,非常方便地和迭代器配合使用
image.png image.png

还有更加简便的方式,把for of替代掉,如下:yield* 后面需要跟一个可迭代对象

image.png

另一个Classroom的例子,非常简单地改为:
image.png image.png
或者这样写
image.png

2、优化多个Promise嵌套

假设有个需求,发送数据给服务器,返回了结果,需要加工后立刻又发送,再接受再发送。

方案1:不断嵌套

最终变成回调地狱
image.png

方案2:链式调用 *

image.png

方案3:生成器 *

image.png

定义一个通用的,自动执行生成器的函数,这个函数可以自动执行任意生成器函数
image.png

image.png 执行

方案4:async / await *

async / await:https://www.yuque.com/yejielin/mypn47/fwsccz

和生成器方案非常像,而且还省下了一个执行函数。

image.png