ES 6 系列之三种异步 - Generator 函数
介绍
Generator 是 ES 6 提供的一种异步编程解决方案。
- 函数定义时,在
funciton后面添加一个星号(*) - 函数体内部使用
yield表达式
1 | // 普通函数 |
Generator 函数的调用方式与普通函数是一样的,在函数名后面加上一对圆括号。
yield 表达式
yield 表达式就是 Generator 的暂停标志。
- 遇到
yield表达式,就会停止执行后面的操作,yield后面表达式的值,作为返回对象的value属性值 - 下次调用
next方法时,才会继续执行代码,直到下一个yield - 如果没有遇到遇到
yield,则运行至结束,看是否有return,如果有,则return后面的值作为返回对象的value - 如果没有
yield或return,则返回value为undefined
1 | function* generator() { |
在上面的代码中,我们可以来感受上面的用途。
只有在调用 next 方法将指针移到这一句时,才会进行求值。
与 return 不同的地方在于,return 不具备记忆功能,也就说,在一个函数中,return 只能执行一次,而 yield 具备记忆功能,可以通过 next 方法继续执行代码。
next 方法
next 普通使用
next 方法就是 generator 函数的内置执行器,如果遇到 yield 时,只有通过调用 next,才会继续执行代码。
而 next 代码的执行值,我们可以打印来看,会是一个对象,带有 value 和 done 两个属性。
1 | function* generator() { |
value值显示的是yield或者return后面的返回值。done是一个布尔值,表示遍历是否结束,true表示结束。- 当然,
return只能有一个,且return之后不能有yield,因为return,就会让done变成true。
next 方法参数
next 方法可以带一个参数,该参数会被当作上一个 yield 表达式的值。
1 | function* generator() { |
当然,这个是会被当作上一个 yield 表达式的值,是在函数内部使用,并不是在 next 返回对象中作为 value 的键值返回。他会替换 generator 函数体内的上一个 yield 值并赋值给我们定义的变量 value。
for…of 循环
for...of 循环可以自动遍历 Generator 函数运行时生成的 Interator 对象,不需要手动调用 next 方法。
1 | function* gen() { |
注意:如果 done 为 true,则会被立刻终止,所有最后一句 return 语句不在循环中。
处理 for...of 循环之外,扩展运算符,解构赋值和 Array.from 方法内部调用的,都是遍历器接口。
都可以将 Generator 函数作为返回的 Interator 对象,作为参数。
1 | function* gen() { |
yield*
yield* 就是 用来在一个 Generator 函数里面执行另一个 Generator 函数。
1 | function* generator1() { |
我们在 generator 函数中,使用了 yield* ,后面调用 generator1 函数。
然后我们就可以直接使用 next 函数,跟普通的 generator 函数一样使用就可以。
Generator.prototype.throw() / return()
throw()
Generator 函数返回的遍历器对象,都会有个 throw 方法,可以在函数体外抛出错误,然后在 Generator 函数体内捕获。
1 | function* generator() { |
在上面的例子中,我们可以看出,第一个 throw 被函数体内部的 catch 语句捕获,然而第二个错误,在内部已经执行过 catch,所有这个错误就被抛出来了,被外面的 try...catch 捕获。
return()
Generator 函数返回的对象中,还有一个 return 方法,可以返回给定的值,并且结束 Generator 函数。
1 | function* generator() { |
从上面的例子,我们可以看出,执行 return 之后,后面的 done 就会变为 true,且传入的参数会作为返回对象的 value 值。
在以后调用时,都会被调整为 undefined,其实就相当于,将 generator 函数中的添加一个 return 。
Generator 函数的异步操作
我们使用一个 readFile,使用 setTimeout 假装调用接口,然后调用 gen.next() 接口返回对象的 value 属性值进行下一步操作。
1 | const readFile = function (fileName, ms) { |
yield 后面用来调用异步函数,然后返回结果输出。