美文网首页工作生活
ES6 Generator函数

ES6 Generator函数

作者: 萘小蒽 | 来源:发表于2019-07-01 11:02 被阅读0次

    Generator函数概念

    Generator函数是ES6提供的一种异步编程解决方案,语法行为与传统函数完全不同。
    对于Generator函数是有多重理解角度。从语法上,首先可以把它理解成一个状态机,封装了很多个内部状态。

    执行Generator函数会返回一个遍历器对象,可以一次遍历Generator函数内部的每一个状态。

    Generator函数特征

    1. function命令与函数名之间有一个星号(*);
    2. 函数体内部使用yield语句定义不同的内部状态(yield是产出的意思);
    3. 函数返回的是一个遍历器对象,须调用next方法才会一次返回不同状态的值。
    function *helloWorldGenerator(){
     yield 'hello';
     yield 'world';
     return 'ending';
    }
    var hw = helloWorldGenerator();
    

    上面代码就定义了一个Generator函数--helloWorldGenerator,它内部有两个yield语句,和一个return语句,即该函数有三个状态:helloworld、和 return语句(结束执行)
    与其他不同函数不同的是,Generator函数调用之后,该函数并不会执行,返回也不是函数的运行结果,而是一个指向内部状态的指针对象,也就是遍历器对象Iterator,在之后,我们必须调用遍历器对象的next方法,使得指正指向下一个状态,每次调用next方法,内部指针就从函数的头部或者上一次停下来的地方开始执行,直到遇到下一条yield语句,或者return语句为止。

    hw.next();
    //{value: "hello", done: false}
    hw.next();
    //{value: "world", done: false}
    hw.next();
    //{value: "ending", done: true}
    hw.next();
    //{value: undefined, done: true}
    

    上面一共执行了四次next方法;

    yield语句

    由于Generator函数返回的遍历器对象只有调用next方法才会遍历下一个内部状态,所以提供了一种可以暂停执行的函数。yield语句就是暂停标志。

    • yield语句,与next方法的运行逻辑
    1. 遇到yield语句就暂停执行后面的操作,并将紧跟在yield后的表达式的值作为返回的对象的value属性值。
    2. 下一次调用next方法时再继续往下执行,直到遇到下一条yield语句。
    3. 如果没有遇到yield语句,就一直运行到函数结束,直到return语句为止,并将return语句后面的表达式的值作为返回对象的value属性的值。
    4. 如果该函数没有return语句,则返回对象的value属性值为undefined,对象的done属性值为true,表示遍历已经结束。
    • yield语句和return语句的区别。

    yield语句和return语句的相似之处在于都能返回紧跟在语句后的表达式的值。区别在于每次遇到yield语句函数会暂停执行,下一次会从该位置继续向后执行,而人团语句不具备位置记忆的功能,一个函数里只能执行一次(或者说一条)return语句,但可以执行多次yield语句。

    • Generator函数不用yield语句。
      这时候就变成了一个单纯的暂缓执行函数。
    function *noyield(){
       console.log('执行了!')
     }
    var  generator = noyield();
    generator.next();
    //执行了!
    
    • 普通函数中不能使用yield语句
    function fn(){
      yield 1;
    }
    fn() // SyntaxError: Unexpected number
    

    for...of中使用Generator函数

    for...of会自动遍历Generator函数,且不需要再调用 next方法.

    function *foo(){
      yield 1;
      yield 2;
      yield 3;
      yield 4;
      return 5;
    }
    for(let i of foo()){
      console.log(i)
    } //1 2 3 4 
    

    上面的代码使用 for...of循环4条yield语句的值,一旦 next方法的返回对象的done属性为true, for...of循环就会终止,且不包含改返回对象,所以上面的return语句返回的6不包括在 for...of循环中。

    for...of语句,扩展运算符(···)、解构赋值和Array.from方法内部调用的都是遍历器接口。这意味着它们可以将Generator函数返回的Iterator对象作为参数。

    function *numbers(){
      yield 1;
      yield 2;
      return 3;
      yield 4;
    }
    //扩展运算符
    [...numbers()]//[ 1, 2 ];
    //Array.from
    Array.from(numbers()) //[ 1,2 ]
    //解构赋值
    let [ x, y ] = numbers()
    x  //1
    y  //2
    //for...of 
    for (let i of numbers()){
        console.log(i)
    }
    //1
    //2 
    

    Generator.prototype.throw();

    Generator函数返回的遍历器都有一个throw方法,可以在函数体外抛出错误,然后在体内捕获。

    var g = function *(){
      while(true){
        try{
           yield;
          }catch(e){
            if(e!='a') throw e 
             console.log('内部捕获',e)    
         }
       }
    } 
    var i = g();
    i.next();
    try{
      i.throw('a');
      i.throw('b');
    }catch(e){
      console.log('外部捕获',e);
    }
    //内部捕获 a
    //外部捕获 b
    

    上面代码中,遍历器对象i连续抛出错误。第一个错误被Generator函数体内catch捕获,然后Generator函数执行完成,于是第二个错误被函数体外的catch语句捕获。

    Generator.prototype.return();

    • Generator函数返回的遍历器对象还有一个return方法,可以返回给定的值,并终结Generator函数的遍历。
    function *numbers(){
      yield 1;
      yield 2;
      return 3;
      yield 4;
    }
    var num = numbers();
    num.next();  
    // {value: 1, done: false}
    num.return('stop');  
    //{value: "stop", done: true}
    num.next();
    //{value: undefined, done: true}
    

    上面函数在遍历器num调用return方法后,遍历终止,返回值的donetrue,之后调用next方法总是会返回true

    • 如果Generator函数内部有try...finally代码块,namereturn方法会推迟到finally代码块执行完再执行。
    function *numbers(){
       try{
          yield 1;
          yield 2;
       }finally{
          yield 3;
          yield 4;
       }
       yield 5;
    };
    var num = numbers();
    num.next();  
    //{value: 1, done: false}
    num.next();  
    //{value: 2, done: false}
    num.return();  
    //{value: 3, done: false}
    num.next();  
    //{{value: 4, done: false}
    num.next();  
    //{value: 6, done: true}
    

    总结

    • Generator函数是分段执行的,yield语句是暂停执行的标记,而next方法可以恢复执行。
    • Generator函数它返回一个遍历器对象,代表Generator函数的内部指针。
    • Generator函数它可以返回一系列的值,因为它可以有人以多条yield语句。
    • yield语句是Generator函数特有的(也仅限于它),将紧跟在yield后的表达式的值作为返回的对象的value属性值。
    • 使用 for...of循环运行的Generator函数,不需要调用next方法,在next的返回对象done属性为true时,for...of循环终止。(扩展运算符,Array.from,解构赋值,都可以使用Generator函数返回的Iterator对象作为参数)

    相关文章

      网友评论

        本文标题:ES6 Generator函数

        本文链接:https://www.haomeiwen.com/subject/msivcctx.html