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


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM