本節的內容,是建立在iterator遍歷器知識的基礎上。所以希望還沒有看上一節的內容的話,最好還是看一看,當然你如果熟悉iterator就沒有那個必要了.

既然你都看到這裡來了,就咱們就接著往下講…

聲明Generator函數

我們要學習的這個新函數叫做:Generator函數,又稱生成器函數,是ES6的一個重要的新特性。

我們來看看這個函數張什麼模樣:

 //聲明一個Hello的Generator函數
    function* Hello(name) {
        yield `hello ${name}`;
        yield `how are you`;
        yield `bye`;
    }

 

上面這個就是Generator函數,乍一看,是不是跟普通的函數沒什麼兩樣?確實很像,但是我們要知道它有兩個重要的區別:

  1. 普通函數用function來聲明,Generator函數用function*聲明。

  2. Generator函數內部有新的關鍵字:yield,普通函數沒有。

PS:函數體內用到了ES6的新特性:字元串模板。第六節的內容,點擊可以查看。

了解了Generator函數的聲明方式,我們又多了兩個疑問:

  1. Generator函數運行起來會發生什麼?

  2. ****關鍵字yield語句的作用是什麼?

調用Generator函數

帶著這兩個疑問我們往下看,我們試著就調用一下這個名字叫Hello的Generator函數,看看會發生什麼:

 //聲明一個Hello的Generator函數
    function* Hello(name) {
        yield `hello ${name}`;
        yield `how are you`;
        yield `bye`;
    }

    //調用Hello函數
    let ite = Hello('前端君');
    //結果:[object Generator]

    ite.next();
    //{value: "hello 前端君", done: false}

    ite.next();
    //{value: "how are you", done: false}

    ite.next();
    //{value: "bye", done: false}

    ite.next();
    //{value: undefined, done: true}

 

看到這裡,估計你也看到了一個熟悉的面孔:next()方法。(上一節iterator遍歷器的內容)。

我們一起看看整個過程發生了什麼:

一開始,我們調用Hello(「前端君」),函數執行後,返回了一個:[object Genrator]生成器對象,我們把它賦值到變數ite中,僅此而已,並沒有做太多的事情。

接著,第1次調用生成器對象ite的next( )方法,返回了一個對象:

{value: "hello 前端君", done: false}

 

第2次調用生成器對象ite的next( )方法,同樣得到了一個對象:

{value: "how are you", done: false}

 

第3次調用生成器對象ite的next( )方法,又得到了一個對象:

{value: "bye", done: false}

 

直到,第4次調用生成器對象ite的next( )方法,返回的對象:

{value: undefined, done: true}

 

看到這裡有沒有發現,這裡生成器的next( )方法的和遍歷器iterator的next( )方法的返回結果是不是一樣?

沒錯,你可以把Generator函數被調用後得到的生成器理解成一個遍歷器iterator,用於遍歷函數內部的狀態。(所以要求大家先學習第十三節iterator遍歷器的知識)

Generator函數的行為

通過上面的案例,我們知道了:Generator函數被調用後並不會一直執行到最後,它**是先回返回一個生成器對象,然後hold住不動****,等到生成器對象的next( )方法被調用後,函數才會繼續執行,直到遇到關鍵字yield後,又會停止執行,**並返回一個Object對象,然後繼續等待,直到next( )再一次被調用的時候,才會繼續接著往下執行,直到done的值為true。

yield語句的作用

而yield在這裡起到了十分重要的作用,就相當於暫停執行並且返回資訊。有點像傳統函數的return的作用,但不同的是普通函數只能return一次,但是Generator函數可以有很多個yield。而return代表的是終止執行,yield代表的是暫停執行,後續通過調用生成器的next( )方法,可以恢復執行

next( )方法接收參數

此外,next( )方法還可以接受一個參數,它的參數會作為上一個yield的返回值,我們來看一下:

//聲明一個Hello的Generator函數
    function* Hello() {
        let res = yield `hello`;
        yield res;
    }
    
    let iterator = Hello();
    //結果:一個生成器對象

    iterator.next();
    //結果:{value: "hello", done: false}

    iterator.next("前端君");
    //結果:{value: "前端君", done: false}

 

注意函數體內的第一個yield關鍵字,我們把它的返回值賦值給了一個變數res。

再看2次next方法的調用:

第1次調用next( )方法,返回的對象屬性value值為「hello」,屬性done值為:fasle,並暫停執行。

第2次next( )方法,傳入參數:字元串「前端君」。此時,第二個yield關鍵字緊跟著的是變數res,而變數res的值正是上一個關鍵字yield的返回值。也就是說這個值正是我們傳入的參數:「前端君」。因為:next( )的參數會作為上一個yield的返回值。

慢慢體會一下,理清邏輯,稍微有點繞。

關鍵字yield*

在一個Generator函數裡面,如果我們想調用另一個Generator函數,就需要用到的關鍵字是:yield*。

我們來看看怎麼玩,程式碼有點長,但是很好理解:

 //聲明Generator函數:gen1   
    function* gen1() {
        yield "gen1 start";
        yield "gen1 end";
    }

    //聲明Generator函數:gen2
    function* gen2() {
        yield "gen2 start";
        yield "gen2 end";
    }

    //聲明Generator函數:start
    function* start() {
        yield "start";
        yield* gen1();
        yield* gen2();
        yield "end";
    }

    //調用start函數
    var ite = start();
    //創建一個生成器
    
    ite.next();
    //{value: "start", done: false}

    ite.next();
    //{value: "gen1 start", done: false}

    ite.next();
    //{value: "gen1 end", done: false}

    ite.next();
    //{value: "gen2 start", done: false}

    ite.next();
    //{value: "gen2 end", done: false}

    ite.next();
    //{value: "end", done: false}
    

 

我們主要看start( )這個Generator函數,其中有兩句程式碼:

   yield* gen1();
    yield* gen2();

 

這裡使用了關鍵字yield*來實現調用另外兩個Generator函數。從後面的多個next( )方法得到的結果看,我們可以知道:

** 如果一個Generator函數A執行過程中,進入(調用)了另一個Generator函數B,那麼會一直等到Generator函數B全部執行完畢後,才會返回Generator函數A繼續執行。**

Generator函數的用途

以上就是對Generator函數的講解介紹,它是ES6的一個很重要的新特性。它可以控制函數的內部狀態,依次遍歷每個狀態;可以根據需要,輕鬆地讓函數暫停執行或者繼續執行。

根據這個特點,我們可以利用Generator函數來實現非同步操作的效果。

原理是:利用Generator函數暫停執行的作用,可以將非同步操作的語句寫到yield後面,通過執行next方法進行回調。

本節小結

總結:Generator函數是一種特殊的函數,可以使用關鍵字yield和next( )實現暫停和繼續執行,而關鍵字yield*專門用於調用Generator函數,看似簡單的特性,在實際開發中卻有極大的用處。
更多前端學習內容文章乾貨請關注我的專欄(不斷更新)

阿里名廠標準web前端高級工程師教程目錄大全,從基礎到進階,看完保證您的薪資上升一個台階

在這裡我給大家準備了很多的學習資料
其實你與阿里工程師的差距只差這些東西