Generator函数,我想大多数人都只是听过,但实际开发中并没有用过吧。至于原因,我分析是因为es6中的promise以及es7中的async、await是异步编程中更好的解决方案,因此Generator函数就被我们选择性地忽略了

inte.jpg

但不常用不代表没有用,理解它的原理我认为还是很有必要的,因此这篇文章就准备好好聊聊它,废话不多说,开搞!

ppx.jpg

什么是Generator函数

Generator翻译过来就是 生成器 的意思,生成什么呢?其实就是生成一个 状态机 以及一个用于遍历状态机的 遍历器对象,它是 协程 在ES6的实现

创建形式上与普通函数大同小异,主要有两个区别

  1. 关键字 function 后面需要跟一个 *****,表明这是一个Generator函数
  2. 函数里面使用 yield 来定义不同的状态

使用上跟普通函数一样,都是使用括号的形式进行调用,但是不同的是Generator函数在调用过后 不会立即执行,而是 返回一个遍历器对象,只有通过遍历器对象才能去 分步执行 函数体

代码示例如下

1
2
3
4
5
6
7
8
9
10
11
12
function* Generator(){
yield 'first step'
yield 'second step'
return 'end'
}

const iterator = Generator() //不会执行函数体,而是返回一个遍历器对象

iterator.next() // 返回一个对象,{value: 'first step', done: false}
iterator.next() // 返回一个对象,{value: 'second step', done: false}
iterator.next() // 返回一个对象,{value: 'end', done: true}
iterator.next() // 返回一个对象,{value: undefined, done: true}

可以看到Generator函数的执行是靠遍历器对象调用 next 方法,一步一步地执行,并且会返回一个对象来装载通过 yield 暴露出来的值,由于这种 可中断 的机制,使其成为一种 异步编程 的解决方案

yield与next

从上文可知,实现Generator函数的关键是使用 yieldnext,本节就准备聊聊它俩

qidai.jpeg

yield翻译过来就是 产出 的意思,通过它可以定义一系列的产出值供next函数调用

而当next调用时,会执行函数体内的语句,直到遇到yield语句就停止下来,并将yield后面的值放在返回对象的value属性里,最后返回这个对象

当再次调用next时,就会从上次停止的地方恢复执行,直到遇到下一个yield或return或函数结尾

通过它俩的配合,可以实现函数的 按需执行 的效果,或者叫 可中断的 执行效果,把函数的执行权交给我们开发者,我觉得这是一种很酷的特性!

另外还有两点需要注意

  1. yield表达式本身 没有返回值,但是可以通过给next函数传递参数,从而去设置 上一个 yield表达式的返回值,这个特性使我们可以动态调整Generator函数内部的代码逻辑,提高代码灵活性
  2. yield表达式是 惰性求值的,也就是说只有当调用next执行到了yield,才会执行对应yield后面的表达式

结语

Generator虽然不常用,但是作为一种让我们理解如何解决异步编程的方案,我觉得还是很有帮助的,所以我才会输出这篇文章,好啦,就写到这里啦,over!