ES6 Generator简单使用与抽象理解
1.什么是Generator,及其简单用法。
先看代码:
注:此处并非最简结构,只是一个总结,如果你对Generator没有初步了解,建议先看恰恰虎的Generator 详解
function* fun() {
yield "a";
yield "b";
}
function* forFun() {
yield "A";
yield "B";
yield "C";
}
function* gen(x, y) {
yield 1;
yield 2;
yield* fun();
let z = yield x+y;
yield z;
let m = yield x+y;
yield m;
for(let item of forFun()){//函数的句柄对象可以通过for of遍历,相当于执行next()直到done为true
console.log(item);//item为yield后的表达式返回值
}
yield "GG"
return "end"//return的值也会在next后返回到字面量对象的value中,并且done为true。
}
var g = gen(2,3);//并不会执行gen函数,而是生成一个指向gen函数的句柄对象
console.log(g.next());//{value: 1, done: false}
console.log(g.next());//{value:2, done: false}
console.log(g.next());//{value:'a', done: false}
console.log(g.next());//{value:'b', done: false}
console.log(g.next());//{value:5, done: false}
console.log(g.next());//{value:undefined, done: false}
console.log(g.next());//{value:5, done: false}
console.log(g.next(999));//{value:999, done: false}
console.log(g.next());
//A
//B
//C
//{value:"GG", done: false}
console.log(g.next());//{value: "end", done: true}
console.log(g.next());//{value: undefined, done: true}
- 声明Generator函数的方式:在函数名前加*即可。
- 执行gen函数:只会生成一个指向gen函数的句柄对象,并不会执行gen函数。
- 执行
g.next()
:开始执行gen函数的某一步,每一次next()都只执行到下一个yield就暂停,并且把yield后面的表达式结果返回到字面量对象的value中。 yield
:为函数的各个步骤间的“隔断”,每次执行next都是执行完下一个yield后面就暂停并将yield后面表达式返回的结果塞到字面量对象的value中,该字面量对象则是执行next后的返回对象。注(并不是执行完yield的整行,比如上面代码的let z = yield x+y;
,只执行x+y
并且将x+y
的值返回就暂停,并不会对z进行赋值,要在下一次next才会执行let z = yield ***
,***是什么请看5)g.next(999)
:next时传参,999会变成上一次yeild的值,也就是let z = yield x+y
,变成了let z = 999
,然后yield z
,就会返回{value:999, done: false}
,如果不传参,就相当于相当于let z = undefined
,然后yield z
,就会返回{value:undefined, done: false}
。- yield* fun() :等同于将gen函数改造成如下
function* gen(x, y) {
yield 1;
yield 2;
yield "a";//就相当于将fun里面的yield直接插进来
yield "b";
let z = yield x+y;
yield z;
let m = yield x+y;
yield m;
for(let item of forFun()){
console.log(item);
}
yield "GG"
return "end"
}
7.for of
循环:使用for of
循环可以循环指向Generator
函数的句柄对象,相当于直接执行它的所有步骤直到返回对象的done
为true
,并且它循环的item为每个yield后表达式的返回值。并且你也可以在循环内部写入yield来将for循环分割成一段一段执行。
8.Generator
函数内部的return
:return
为非必须,如果存在的话则在最后done
为true
时,value
的值即是return
后面表达式的值。
9.Generator
函数的句柄对象的return()
方法:
function* gen(x,y){
yield 1;
yield 2;
yield 3;
}
var g = gen();
g.next();//{value: 1, done: false}
g.next();//{value: 2, done: false}
g.return(5);//{value: 5, done: true}
g.next();//{value: undefined, done: true}
return()
方法作用如上,即可以截断yield
,并且传入的参数即使返回的对象value
值,done
会被置为true
Generator的抽象理解(流水线)
- Generator函数就像一个流水线的图纸,
- 当执行该函数时就相当于创建了一条流水线,但是并未开启,如果在执行函数时传入了参数,就相当于流水线的原材料,
- 在执行next()时就相当于开启了流水席线,
- 当产品撞到了yield(即代码走到了yield)流水线就会被暂停,
- 暂停后会把这一阶段的半成品交给操作员,操作员决定是否对该半成品进行其他操作,或者加入新的原材料,或者不进行操作,如果需要进行操作就将字面量对象的value进行计算在下一次next()时当作参数传入,如果需要加入新的原材料就将新的值在下一次next()时当作参数传入,如果不需要任何操作即把最近一次的next()的返回对象的value当作参数执行下一次next
- 当一次步骤结束(next结束)我们发现需要插入其他工序,即使用
yield*自定义Generator函数()
- 当我们发现只需要无脑开动流水线直到结束,我们就可以使用for of循环
- 当我们发现需要提前终止流水席生产,那就执行return().
Generator的作用
Generator的最大特点就是一个可以暂停并且重启的函数,并且在暂停重启间可以注入新的参数,这样就给开发流程带来了更多的灵活性,可以使代码像一个流水线一样,随时暂停开启并且注入新的参数。虽然常规开发你在自己调用一系列的函数过程中也可以使用各种if判断来决定函数的执行与不执行,也能达到控制代码流程的作用,但是Generator给了我们更加美观,规范化,便捷的开发方式,网上很多人说Generator用来解决回调地狱,其实回调地狱直接使用Promise或者async await更加方便实用,使用 Generator反倒会不易读。(以上均为个人浅薄观点,如有错误请评论区指出)。