generator-yield到底是个啥
咱们通过上篇文章的简单介绍,已经了解到yield是放弃执行,放弃现在继续执行的权利,把权利让给别人,什么时候想继续执行的时候,再调一次就好。接下来咱们说两件事,就是yield是一个很有意思的东西,它可以传参,也可以有返回值。(提醒:接下来的东西略微有点难懂,大家不要过于纠结和较真,后面应用的时候,很多东西就自然通顺了)
一、yield可以传参
先来一个函数
function *show() { alert('a'); let a = yield; alert(a); alert('b'); } let gen = show(); gen.next(12); gen.next(5);
通过函数我们可以看到,定义a接收了yield传进来的参数,现在请大家和我玩个游戏,猜猜看a是几
好了,不卖关子了,咱们执一下看看
那么现在反过来就有一个问题了,可能有些人会说,等会,我有点看不明白了,我怎么觉得应该是12呢,怎么回事呢?
好,简答的说一说为什么是5,这个实际上来说是yield里面特别好玩的一件事,大家允许我用一个小小的方法(用一张图来说明)
从上面的图上,我们可以看到画红框的地方,执行的是我用红笔圈起来的这部分代码,画绿框的地方,执行的是用绿笔圈起来的代码
我们把它简答的看做两个过程,第一个过程传进去的参数是12,第二个过程传递进去的参数是5,所以我们的a接收到的是我们第二个过程里传进去的5,没问题吧,当然还是那句话,别较真,认真你就输了,大家都懂的哈
那么所以通过yield传参的时候,第一个next是废的,传什么都不好使,传什么都白传,这个时候大家可能会问了,那我想给第一个过程传参,该怎么办呢?你说怎么办,不就是我们过去的传参方法嘛,我们传一个num1,一个num2,然后接收一下,咱试试哈
function *show(num1, num2) { alert(`${num1}, ${num2}`); alert('a'); let a = yield; alert(a); alert('b'); } let gen = show(99, 88); gen.next(12); gen.next(5);
这样运行的话,可以正常接收我们传进来的参数
而通过这个过程,我们可以看到,第一个next对于传参来说,是废的,没办法给yield传参的,想给第一个过程传递参数,就得像正常函数一样,通过函数(参数)的形式来
二、yield可以返回
咱们刚刚说了yield的第一个功能是可以往里面传东西,下面我们说一说yield的另一个功能,可以往外吐东西(返回)
咱们在上面把一个大的generator函数划分为几个过程,通过yield来分割这几个过程,我们可以理解为中间结果
举个最简单的例子,就像我做菜一样,当然我这人不会做菜,连锅都能糊了,可好玩了,有时间再和大家慢慢扯哈
就拿做菜来说,我们可以分为几个步骤:洗菜、切菜、炒菜
我们可以认为,在最开始输入了刚买回来的菜,也相当于我们函数的参数,接下来的每一步都有一个半成品(刚买回来的菜),它也就相当于我们下一步的输入,最后变成一盘炒好的菜。说白了,在这个函数里,每一步都会有一个中间结果,也算是中间的输入。
从第一步的yield可以传参到第二步的yield有个中间结果,下面我们看一看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(); console.log(res2); //{value: undefined, done: true}
咱们还是和刚才一样,定义一个generator函数,定义两个过程,将next函数的返回值打印出来之后可以看到,第一个过程中返回了
{value: 12, done: false},第二个过程返回了{value: undefined, done: true},在第一个过程里,value是12,done是false,done是完成的意思,因为第一个过程并不是函数结束,所以返回的是false,而第二个返回值中,value为什么是undefined呢?
原因很简单,咱们在上面的切菜图上说的很明白了,这个阶段是咱们函数的最后一道工序,最后一道工序就没有yield了,所以也就没有返回值了,想返回东西的话,就只能用return来返回。
请允许我用一个更俗的例子来把这事说的更清楚。
三、yield到底是个啥
咱们用伪代码定义了一个generator函数,咱名字就叫炒菜,最初的参数是刚从菜市场买回来的菜,第一步完成洗菜的过程,然后通过yield把洗好的菜传递给下一个过程,下一个人拿到干净的菜之后把它切成块,切成丝,再通过yield传给下一个人,然后下一个人拿到切好的菜之后,就可以炒了,最后我们得到熟的菜,把它return出去。下面咱们画一画,帮助大家更好的理解
首先蓝色框里画的是第一个过程,红色框是第二个过程,绿色框是第三个过程,而中间的yield就相当于隔在他们中间的“墙”,“墙”之前是一个过程,之后是另一个过程。在过程一的输入是(菜市场买回来的菜),做了一些工作之后,把洗好的菜(中间结果)返回出去,在“墙”的那边,得到的是我们返回的干净的菜,然后咣咣咣一顿切之后,得到了切好的菜(中间结果),有了中间结果之后,在“墙”的那一边有人得到了我们的中间结果,然后拿去炒,得到熟的菜,最终的结果return出去。总的来说,最初的东西走参数,最终的结果走return,其实generator咱要这么说的话,也不难,就是中间步骤可以返回出去,那边怎么着怎么着,反正就这点事。
相信通过上面有些神经病的讲解之后,相信大家应该比较彻底的了理解了generator以及它的yield,还是那句话,较真你就输了。
接下来呢,咱们要干件事了,既然明白了,既然理解了,接下来趁热打铁,咱们用一用它,中国有句古话“光说不练....”,嗯,大家都懂,我就不多说了,咱们来用一用它,看看它能干啥,generator其实在很大程度上和Promise很像,都是用来解决异步操作相关问题的。废话不多说,咱们在下一篇文章中直接拿来玩,感兴趣的话,可以继续关注我。