咱們通過上篇文章的簡單介紹,已經了解到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很像,都是用來解決異步操作相關問題的。廢話不多說,咱們在下一篇文章中直接拿來玩,感興趣的話,可以繼續關注我。