迭代器的基础功能可以辅助我们完成很多任务,通过生成器创建迭代器的过程也很便捷,迭代器也可以被用于完成一些复杂任务。
给迭代器传递参数
给迭代器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中执行错误的约定,错误放在第一个参数中。