迭代器的基础功能可以辅助我们完成很多任务,通过生成器创建迭代器的过程也很便捷,迭代器也可以被用于完成一些复杂任务。
给迭代器传递参数
给迭代器next()方法传递参数,则这个参数的值会替代生成器内部上一条yield语句的返回值。
第一次调用next()方法,无论传入什么参数都会被丢弃。因为第一次调用next()方法前不会执行任何yield语句。
第二次调用next()方法传入数值4做为参数,它最后被赋值给生成器函数内部的变量first。在一个含参yield语句中,表达式右侧等价于第一次调用next()方法后的下一个返回值,表达式左侧等价于第二次调用next()方法后,在函数继续执行前得到的返回值。第二次调用next()方法传入的值为4,他会被赋值给变量first,函数则继续执行。
代码执行过程为
在迭代器中抛出错误
通过throw()方法,当迭代器恢复进行时可令其抛出一个错误。这种主动抛出错误的能力对于异步编程而言至关重要,从而增强生成器内部的编程弹性。
调用throw()方法后,在继续执行let second求值前,错误就会被抛出并阻止代码继续执行。可以使用try...catch代码块来捕获这些错误。
在变量second赋值前会主动抛出错误,catch代码块捕获到错误后,将second变量赋值为6,下一条yield语句继续执行后。
调用throw()方法后也会像调用next()方法一样返回一个结果对象,由于在生成器内部捕获了这个错误,因而会继续执行下一条yield语句。next()方法使迭代器继续执行,throw()方法也会使迭代器继续执行,并同时抛出一个错误,在此之后的执行过程取决于生成器内部的代码。
生成器返回语句
由于生成器也是函数,因此可以通过return语句提前退出函数执行。在生成器中,return表示所有操作已经完成,属性done被设置为true,如果同时提供了相应的值,则属性value会被设置成这个值。
return语句后面的yield语句不会被执行。通过return语句指定的返回值,只会在返回对象中出现一次,后续调用返回对象中,value属性会被重置为undefined。
展开运算符与
for-of循环语句会直接忽略通过return语句指定的任何返回值,只要done一变为true就立即停止读取其他的值。
委托生成器
某些情况下,需要将两个迭代器合二为一,这时可以创建一个生成器,再给yield语句添加一个星号,就可以将生成数据的过程委托给其他生成器。
生成器createCombinedInterator()先后委托了另外两个生成器createNumberIterator()和createColorInterator()。每一次调用next()方法就会委托相应的迭代器生成相应的值,知道两个迭代器无法返回更多的值,此时执行最后一条yield语句并返回true。
yield *也可以用于字符串,此时将使用字符串的默认迭代器。
异步任务
异步处理一般方式是使用回调函数,由于生成器支持在函数中暂停代码执行,所以有更优雅的处理方式。
执行yield语句会暂停当前函数的执行过程并等待下一次调用next()方法,可以创建一个函数,在函数中调用生成器生成相应的迭代器,从而不用回调函数的基础上实现异步调用next()方法。
函数run接受一个生成器函数作为参数,这个函数定义了后续要执行的任务。首次调用迭代器的next()方法,返回的结果被存起来后续使用,step函数会检查result.done的值,来确定是否还有任务需要执行。
给任务执行器传递数据最简单的办法是,将值通过迭代器的next()方法传入做为yield的生成器供下次使用。
上面是在多个yield调用间来回传递静态数据,而等待一个异步过程有点不一样。可以给yield一个函数,这个函数返回一个可以执行回调函数的函数。需要修改一下任务执行函数,当result.value是一个函数时,执行这个函数,在将结果传给next()方法。
这里回调函数遵循了Node.js中执行错误的约定,错误放在第一个参数中。