• Generator 函数的用法


    Generator  函数是ES6提供的一种异步编程解决方案。

    Generator 语法行为与传统函数完全不同。

    Generator 函数有多种理解角度。语法上,首先可以把它理解成,Generator函数是一个状态机,封装了多个内部状态。

    执行Generator函数会返回一个遍历器对象,也就是说,Gnerator 函数除了状态机,还是一个遍历器对象生成函数。返回的遍历器对象,可以依次遍历Generator函数内部的每一个状态。

    形式上,Generator函数是一个普通函数,但是有两个特征。一是, function 关键字与函数名之间有一个星号;二是,函数体内部使用 yeild 表达式,定义不同的内部状态(yield在英语里的意思就是“产出”)。

    例子:

    function* helloWorldGenerator() {
      yield 'hello';
      yield 'world';
      return 'ending';
    }
    var hw = helloWorldGenerator();

    上边代码定义了一个Generator函数 helloWorldGenerator ,它内部有两个yield表达式(hello 和 world),  即该函数有三个状态: hello ,  world 和 return 语句 (结束执行)。

    然后,Generator 函数的调用方法与普通函数一样,也是在函数名后加上一对圆括号。不同的是,调用Generator函数后,该函数并不执行,饭hide也不是函数运行结果,而是一个指向内部状态的指针对象,也就是遍历器对象。

    下一步,必须调用遍历器对象的next 方法,使得指针移向下一个状态。也就是说,每次调用next 方法,内部指针就从函数头部或上一次停下来的地方开始执行,直到遇到下一个 yield 表达式(或 return 语句)为止。换言之,Generator函数是分段执行的, yield表达式时暂停执行的标记,而 next 方法可以恢复执行。

    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 方法

    第一次调用 Generator函数开始执行,直到遇到第一个yield表达式为止,next 方法返回一个对象,它的 value属性 就是当前 yield表达式的值 hello, done 属性的值 false, 表示遍历还没有结束。

    第二次调用,Generator函数从上次 yield 表达式停下的地方,一直执行到下一个 yield表达式。 next 方法返回的对象的 value 属性就是当前 yield表达式的值 world , done属性的值 false, 表示遍历还没有结束。

    第三次调用,Generator函数从上次yield 表达式停下的地方,一直执行到return 语句(如果没有 return 语句,就执行到函数结束)。 next 方法返回的对象的 value 属性,就是紧跟在return语句后面的表达式的值(如果没有 return 语句,则value属性的值为 undefined),done 属性的值 true,done属性的值 true, 表示遍历已经结束。

    第四次调用,此时Generator函数已经运行完毕, next 方法返回对象的value属性为 undefined, done属性为 true。以后再调用 next 方法,返回的都是这个值。

    总结一下,调用Generator函数,返回一个遍历器对象,代表Generator函数的内部指针。以后每次调用遍历器对象的 next 方法,就会返回一个有着value 和 done两个属性的对象。 value属性表示当前内部状态的值,是yield表达式后面那个表达式的值; done是一个布尔值,表示是否遍历结束。

    yield 表达式

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

    (1)、遇到yield表达式,就暂停执行后面的操作,并将紧跟再 yield 后面的那个表达式的值,作为返回的对象的 value 属性值。

    (2)、下一次调用 next() 方法时,再继续往下执行,知道遇到下一个 yield 表达式; 

    (3)、如果没有遇到新的yield表达式,就一直运行到函数结束,直到return 语句为止,并将return 语句后面的表达式的值,作为返回的对象的 value 属性值。

    (4)、如果该函数没有return 语句,则返回的对象的value 属性值为 undefined。

    需要注意的是, yield 表达式后面的表达式,只有当 next 方法,内部指针指向该语句时才执行,因此等于为JavaScript提供了手动的“惰性求值”的语法功能。

    function* gen() {
      yield  123 + 456;
    }

    上面代码中, yield 后面的表达式 123 + 456 , 不会立即求值,只会在 next 方法将指针移到这一句时,才会求值。

    yield 表达式与 return 语句既有相似之处,也有区别。相似之处在于,都能返回紧跟再语句后面的那个表达式的值。区别在于每次遇到 yield, 函数暂停执行,下一次再从该位置继续向后执行,而return 语句不具备位置记忆的功能。一个函数里面,至多只能执行依次 reuturn 语句,但是可以执行多次(或者多个)yield 表达式。因此,拥有 yield表达式的 Generator生成了一系列的值。

    yield 表达式如果用在另一个表达式中,必须放在圆括号里。

    function* demo() {
      console.log('Hello' + yield); // SyntaxError
      console.log('Hello' + yield 123); // SyntaxError
      console.log('Hello' + (yield)); // OK
      console.log('Hello' + (yield 123)); // OK
    }

    yield 表达式用作函数参数或放在赋值表达式的右边,可以不加括号

    function* demo() {
      foo(yield 'a', yield 'b'); // OK
      let input = yield; // OK
    }

    任何一个对象的 Symbol.iterator方法,等于该对象的遍历器生成函数,调用该函数会返回该对象的一个遍历器对象。因此,可以把Generator赋值给对象的Symbol.iterator属性,从而使得该对象具有Iterator接口。

    var myIterable = {};
    myIterable[Symbol.iterator] = function* () {
      yield 1;
      yield 2;
      yield 3;
    };
    [...myIterable] // [1, 2, 3]

    上面代码中,Generator函数赋值给 Symbol.iterator属性,从而使得 myIterable 对象具有了 Iterator接口, 可以被 ... 运算符遍历了。

    Generator函数执行后,返回一个遍历器对象。该对象本身也具有 Symbol.iterator属性,执行后返回自身。

    function* gen(){
      // some code
    }
    var g = gen();
    g[Symbol.iterator]() === g
    // true
  • 相关阅读:
    JavaScript----特效代码
    坑!vue.js在ios9中失效
    MySQL的ibdata1文件占用过大
    Ubuntu搭建Gitlab服务器
    Logstash+Kibana部署配置
    Kafka+Zookeeper集群搭建
    ES5.0集群搭建
    Kibana使用高德地图
    Zabbix安装客户端agent(windows和Centos7)
    Centos/Rhel7部署Zabbix监控(部署篇之服务器篇)
  • 原文地址:https://www.cnblogs.com/zhishiyv/p/15913212.html
Copyright © 2020-2023  润新知