Generator
前言
本人是一个小公司的前端,很菜ing。
之前有看过一篇关于ES6的文章,里面讲了扩展运算符、Symbol、Set和Map数据结构等等,文章最后我看到了一个从来没见过的Generator,后面就去学习,立贴记录一下。
Generator是什么
Generator函数是ES6引入的,主要就是用于解决异步编程。
Generator最大的特点就是可以交出函数的执行权(暂停执行)。
他和普通函数的写法不太一样,主要是有两种不同
-
function关键词与函数名之间有一个星号
-
Generator函数体内部使用yield语句,可以定义不同的内部状态(内部状态就是内部的值,在不同的时候是不一样的)
本质上,整个Generator函数就是一个封装的异步任务,或者说是异步任务的容器
yield命令就是异步不同阶段的分界线(PS: yield 不同于 return )
Generator实现
function* fn(){
yield 'a';
yield 'b';
yield 'c';
yield 'd end...';
}
var fn = fn()
这时,这个fn是一个迭代器的引用
现在看一下迭代器对象的例子
function* fn(){
var n = 1;
yield ++n;
yield ++n;
yield ++n;
}
//这里声明了两个迭代器
var a = fn()
var b = fn()
console.log(a.next()) //2
console.log(a.next()) //3
console.log(b.next()) //2
console.log(a.next()) //4
从上面两个迭代器运行结果来看,每个迭代器之间都是相互独立的,作用域独立互不干扰
当你调用了一个迭代器内部的.next()方法,Generator函数内部的指针,就从上一次停下的地方继续运行,直到遇到下一个yield语句或者return
最后为什么说他是迭代器呢,因为他得把里面的yield语句都走一遍
yield就像录音机上的暂停键, .next()就像录音机上的继续键
yield语句只能在Generator函数中,普通函数不行
启动方法为 .next()
作用是分阶段的执行Generator函数
每次调用.next()方法都会返回一个对象 表示当前阶段的信息
value属性(表示当前的值)
done属性(是否执行结束) -true 表示当前函数执行完了 -false 表示当前函数还未执行完
function* fn(){
yield 'a';
yield 'b';
yield 'c';
yield 'd end...';
}
var fn = fn()
//这里执行的是第一个yied语句
console.log(fn.next())
//这里执行的是第二个yied语句
console.log(fn.next())
//这里执行的是第三个yied语句
console.log(fn.next())
//这里执行的是第四个yied语句,done的值为true
console.log(fn.next())
//这时value的值为undefined
console.log(fn.next())
Generator传参
Generator函数中的.next()方法可以接收参数
-
传入的参数,其实是把上一个yield语句返回的值给覆盖掉
-
第一个.next()方法其实是启动器,在他之前没有yield语句,所以给第一个.next()方法传参是没有意义的
看例子
function* fn(){
var n = 1;
var v = yield n + 10;
console.log('a-----' + v)
yield ++n;
yield ++n;
}
var fn = fn()
console.log(fn.next()) //11
/*
第一个.next,他返回的value是11,1+10返回
var v = yield n + 10; 这是一个赋值运算,到这个yield的时候v还没有赋值就遇到第一个yield就停止了
*/
fn.next('abc') //abc
/*
第二个.next()
传入的参数其实就是把上一个yield语句的返回值覆盖了;
上一个yield语句的值是 n+10
然后又传入了abc
那么上一个yield语句的值就变成了 yield = abc ,随后又赋值给了v
所以打印的值console.log('a-----' + v) 是 a-----abc
然后又遇到下一个yield就又停止了
*/
console.log(fn.next()) //3
/*
第三个.next()
第二次传入的参数,其实是把上一个yield语句返回的值给覆盖掉
但是,他并没有修改之前声明变量n的值
n的值依然是1,然后经过两次++n ,1 + 1 + 1所以返回值为3
*/
这个例子是最能说明Generator函数用途的例子
就是可以通过.next方法,去分阶段的注入数据
让函数分阶段的给出不同的返回值
Generator循环
Generator函数支持for of循环
用来迭代Generator函数在执行时
生成的那个迭代对象
看例子
function* fn(){
yield 'a';
yield 'b';
yield 'c';
yield 'd end...';
}
var fn = fn()
for(var i of fn){
console.log(i) // a b c
}
就是可以把迭代器的所有值迭代出来
具体应用场景他不是一个单独的返回值可能是一个函数或者其他东西可以把他批量的迭代出来全部求值
总结
虽然Generator函数能够实现异步编程,但实际上我们很少用它来实现异步,因为ES7引入的 async 函数对Generator函数的流程又做了一层封装。但作为一个开发者,我们有必要了解一下Gernerator的基本使用以及简单的实现的原理,方便在特殊的场景中解决问题。