1. 程式人生 > >ES6 新特性之Generator

ES6 新特性之Generator

1:基本概念

實際上Generator就是遍歷器的一個生成器,我們可以用Generator來生成一個遍歷器。Generator有兩個明顯的特點:第一個是function關鍵字與函式名之間有一個星號,一般而言是將兩者寫在一起的。第二個是在函式體內部有一個yield的關鍵字。

    function* generator(){
        yield 1;
        yield 2;
        return 3;  //return代表next的結束,對應著Generator遍歷器的結束
    }
    const firstGenerator = generator();
    //
    firstGenerator.next()
    { value: 1, done: false }
    firstGenerator.next()
    { value: 2, done: false }
    firstGenerator.next()
    { value: 3, done: true }
    firstGenerator.next()
    { value: undefined, done: true }
    firstGenerator.next()
    { value: undefined, done: true }

2:執行過程

呼叫Generator函式後並不執行,第一次呼叫不執行,只有在呼叫next的時候才會真正的執行。

    function* generator(){
        console.log(1);
        yield 1;
        console.log(2);
        yield 2;
        console.log(3)
        return 3;
        console.log(4);
    }
    const gen = generator();

呼叫next方法開始執行,指標移向下一個狀態

    function* generator(){
        console.log(1);
        yield 1;
        console.log(2);
        yield 2;
        console.log(3)
        return 3;
        console.log(4);
    }
    const gen = generator();
    gen.next();
    
    // 1
       { value: 1, done: false }

執行到yield或者是return語句,每一個next只能走到下一個yield或者是直接跨到了return。

    function* generator() {
      console.log(1);
      yield 1;
      console.log(2);
      yield 2;
      console.log(3);
      return 3;
      console.log(4);
    }
    const g = generator();
    g.next();
    g.next();
    
    // 1
       2
       { value: 2, done: false }

當next時,會從上一次暫停位置開始執行,直到return,return是退出next的一個標誌。

    function* generator() {
      console.log(1);
      yield 1;
      console.log(2);
      yield 2;
      console.log(3);
      return 3;
      console.log(4);
    }
    
    const g = generator();
    g.next();
    g.next();
    g.next();
    g.next();
    
    // 1
       2
       3
       { value: undefined, done: true }

3:Generator方法

  • next,如果傳了引數被當作上一個yield表示式的返回值,說明next是可以傳引數的,如果沒傳時undefined。
    function* generator(x) {
      var y = 3 * (yield (x + 3));
      var z = yield (y / 2);
      return (x + y + z) * 2;
    }
    
    const gen1 = generator();
    
    // gen1.next(); 
       { value: NaN, done: false } 
       gen1.next();
       { value: NaN, done: false } */
       gen1.next();
       { value: NaN, done: false } */
       gen1.next();
       { value: undefined, done: true }
    function* generator(x) {
      var y = 3 * (yield (x + 3));
      var z = yield (y / 2);
      return (x + y + z) * 2;
    }
    
    const gen2 = generator(10);
    gen2.next();
    // { value: 13, done: false } 
    /*
    x = 10
    13 = 10 + 3
    */
    
    gen2.next(10);
    // { value: 15, done: false }
    /*
    y = 30
    15 = 3 * 10 / 2
    */
    
    gen2.next(10);
    // { value: 100, done: false }
    /*
    z = 10
    100 = (10 + 10 + 30) * 2
    */
    
  • throw,函式外丟擲錯誤在Generator函式體內捕獲
    function* generator(x) {
      try {
        yield;
      } catch (err) {
        console.log('inner error', err);
      }
    }
    
    const g = generator();
    g.next();
    // { value: undefined, done: false }
    
    g.throw(new Error('123'))
    // inner error Error: 123
    
  • return ,終結當前的Generator函式。

4:Generator函式應用

  • yield*,在Generator函式內部呼叫另一個Generator函式,無需手動遍歷。
    function* generator1(){
      yield* [1, 2, 3];
    }
    generator1().next();
    // { value: 1, done: false } 
    
    function* generator2(){
      for (var value of [1, 2, 3]) {
        yield value;
      }
    }
    generator2().next();
    // { value: 1, done: false } 
    
    function* generator3(){
      yield [1, 2, 3];
    }
    generator3().next();
    // { value: Array(3), done: false }
    

5:Generator函式應用

  • for of,遍歷return前的資料
    function* generator() {
      yield 1;
      yield 2;
      yield 3;
      return 4;
    }
    
    for (let s of generator()) {
      console.log(s);
    }
    //  1
        2
        3
    	```	
    
  • 狀態機
    const status = function* () {
      while (true) {
        console.log('On');
        yield true;
        console.log('Off');
        yield false;
      }
    }();
    status.next();
    
    // On
       {value: true, done: false}
    
  • 網路請求
    import axios from 'axios';
    
    function* generator(){
      const url = 'https://xxx.xxx.com';
      const result = yield fetch(url);
      return result();
    }
    
  • 非同步