generator
Generator 是一种可以暂停的函数,通过使用 yield 来进行控制。
基本
本文通过一段代码来解释 generator 的机制。
generator 一种特殊的函数,其通过在 function 和函数签名之间加上一个 * 来定义,* 的位置没有要求,因此,以下任何一种方式都是合法的:
首先通过调用 foo() 来生成一个迭代器。接着通过调用这个迭代器的 next 方法可以控制该函数的流程。
当调用第一个 next 的时候,会运行到第一个 yield 处,然后停止该函数的运行。
yield 关键字用来暂停函数,当函数运行到带有 yield 关键字的地方的时候,就会暂停该函数。当 yield 后面有一个值得时候,会将该值传出。
在上面一段代码的 //1 处,it.next() 返回了 { value: 5, done: false }。
再看 //2 处的 it.next(10),这次给 next 传了一个值,值为 10,这相当于将上次出现 yield 的地方赋值为 10,也就是说,var a = yield 5; 处变为 var a = 10;,因此变量 a 被赋值为 10,接着,函数继续运行,一直运行到下一个 yield 处,也就是 console.log(yield a),当运行到这个 yield 的时候,函数暂停,于是 console.log(yield a) 最终还没有被调用。此时 yield a 将 a 值传出,所以在 //2 处返回的值为 { value: 10, done: false }。
接着继续调用 //3 处的 it.next(20),这次传入了 20,上次出现 yield 的代码变为 console.log(20),因此控制台输出 20,同时,函数一直运行到 return a 处。此时,//3 处的代码返回 { next: 20, done: true }。因为函数已经运行完成了,所以 done 变为 true。done 是用来指示迭代器是否运行完成的标志,当 done 为 true 的时候,就表明迭代器已经运行完成了。
接着继续调用 //4 处的 it.next(30),但这次函数已经运行完成了,所以返回了 { next: undefined, done: true }。
异常捕获
可以调用 throw 方法来向函数传入一个错误,如果错误没有被函数处理,则错误会被重新抛出。
来看看上面一段代码,首先运行了一遍 it.next(),于是函数停在了 yield 处,yield 处于一个 try 中,此时如果有错误抛出,则会被 catch 接收到,然后调用了两次 it.throw,分别传入 a 和 b,第一次传入的 a 被函数内部的 catch 捕获了,但第二次则是被外部的 catch 捕获,因为函数内部的 catch 已经运行过一遍了。
生成器委托
通过前面添加 yield * 在一个生成器函数中调用另一个生成器函数。看看输出就可以理解流程了:
