我们知道generator函数是es6引入的一种异步编程解决方案,那么问题就来了,我们前面知道promise对象也是用于解决异步问题的,那他们两个有什么区别呢?什么情况下应该用哪种方案呢?
普通函数与generator函数
首先我们知道普通的函数在执行的过程当中是一路走到底的,这就像是你坐飞机,在路上你不可能跟乘务长说停一下,你要下去,这是不可能的。但是generator函数可以,它中间能停!这就好比你坐出租车,中间你说你上楼拿个东西,让司机等你一下,是可行的。
什么时候暂停呢?
既然我们已经说到了在generator函数执行的过程当中,是可以暂停的,那么它到底什么时候暂停呢?这个时候就有了yield。
同时我们也会发现,当你创建一个genrator函数并且去执行它的时候,它是不会立即执行函数体内的东西的,而是创建了一个generator对象,这个对象当中有一个很重要的函数叫做next,
有了next这个函数,我们就可以在暂停之后继续执行下去。
function *show(){
alert('a');
yield;
alert('b');
}
var gen = show();
console.log(gen); //一个generator对象
gen.next();
gen.next();
从上面的解释当中我们其实可以看出,generator函数其实是有些像“揣一脚,走一步”的。
我们让这个函数暂停的原因,其实是因为我们需要去忙活一些事情,比如说我们去请求一些数据,这是一个异步操作,是需要花费时间的。需要让他等我们一下。
那么genrator函数是怎么实现走走停停的呢?
其实它的本质是用一个generator函数生成了很多个函数。
那么现在我们来看一些比较具体的例子:
yield它既可以用来返回中间结果,也能传参
function *show(){
alert('a');
let a = yield;
alert('b');
alert(a); //5
}
var gen = show();
gen.next(12);
gen.next(5);
为什么最后一次alert会输出5呢?我们可以这样看,其实yield就像是一堵墙,把函数分成了两个部分,执行第一个next的时候,是执行的yield之前的部分,而执行第二个next的时候,执行的其实是yield之后的部分,所以这个时候a是等于5的,就像下面这张图画的这样
现在我们来看一下yield保存中间结果的情况
function *show(){
alert('a');
yield 12;
alert('b');
}
let gen = show();
let res1 = gen.next();
console.log(res1); //{value:12,done:false}
let res2 = gen.next();
结果是如你所料的,value为12
那么现在我们可以更为清晰的用一张图来讲解yield保存中间结果的过程如果我们想要在最开始的alert中打印出输入值,那么很明显我们可以在generator函数中加入参数,用来保存中间结果的是yield,而最终返回的“煮熟的菜”是通过return来返回的。
那么generator和promise到底什么时候用哪个呢?
如果你需要在异步操作之后进行逻辑判断去做一些事情,这时候如果异步操作多了,那么使用promise就会比较麻烦,而使用generator就会比较的简单,因为你只需要拿yield保存的值来做判断即可,这个写法就非常像是在写一个同步函数。
所以当在执行异步操作之后,需要夹杂复杂逻辑判断的时候用generator比较是比较好的选择,而你需要执行一堆异步操作,并且他们没有什么复杂逻辑判断的时候,使用promise是比较好的选择。
//图片来源于网络