美文网首页
ECMAScript6--17.Generator

ECMAScript6--17.Generator

作者: 飞菲fly | 来源:发表于2017-10-24 01:17 被阅读47次

1.Generator

  • 基本概念
    • 异步编程的一种解决方案;
    • Generator包含多个步骤,遇到每一个步骤的标志是yield或者return,遇到yield或者return,这步就停止了,不会向下运行了;进行下一步要调用next函数,直到结束;
    • next函数的用法
    • yield*的语法

2.generator返回的就是一个iterator接口;

通过next的方式不断去做函数体内部的几个阶段,执行tell的时候,会遇到第一个yield的时候停下来,执行完了yield之前的语句,调用next的时候会执行第一个yield;在执行next的时候,会执行到下一个yield或者return,以此类推,从而保证了这个函数体内部看上去是一个异步操作的过程;

generator基本定义:

    {
      let tell = function*(){
      yield 'a';
      yield 'b';
      return 'c'
    };
   
     let k = tell();
   
     console.log(k.next());
     console.log(k.next());
     console.log(k.next());
     console.log(k.next());
     //打印结果:
    Object{value:"a",done:false}
    Object{value:"b",done:false}
    Object{value:"c",done:true}
    Object{value:undefined,done:true}

    }

3.generator函数和iterator接口的关系;

  • 任意一个对象的iterator接口都是部署在Symbol.iterator属性上;

  • generator函数就是一个遍历器生成函数,所以可以直接把它赋值给
    Symbol.iterator从而使这个对象也具备了iterator接口;

  • generator也可以作为遍历器的返回值;

      {
        let obj ={};
        obj[Symbol.iterator] = function*(){
            yield 1;
            yield 2;
            yield 3;
       }
      
        for(let value of obj){
            console.log('value',value);   
       }
      //value 1
      //value 2
      //value 3
     }
    

4.什么情况下generator有这最大的优势呢?

  • 状态机
    比如:需要a、b、c三种状态描述一种事物,这种事物只存在abc三种状态;a-b-c-a;
    • 调用next方法走到第一个yield,下一个next会到B,在next到C,在next
      的时候,因为while(1)会无限循环,又回到A,B-C-A-B...;
{
    //状态机
    let state =function*(){
        //while(1)永远循环
        while(1){
            yield 'A';
            yield 'B';
            yield 'C';
        
        }
    };

    let status = state();
    console.log(status.next());
    console.log(status.next());
    console.log(status.next());
    console.log(status.next());
    console.log(status.next());
    //输出结果:
    Object{value:"A",done:false}
    Object{value:"B",done:false}
    Object{value:"B",done:false}
    Object{value:"A",done:false}
    Object{value:"B",done:false}

}

5.async

{
    let state =async function(){
        while(1){
            await 'A';
            await 'B';
            await 'C';
        
        }
    };

    let status = state();
    console.log(status.next());
    console.log(status.next());
    console.log(status.next());
    console.log(status.next());
    console.log(status.next());
    //输出结果:
    Object{value:"A",done:false}
    Object{value:"B",done:false}
    Object{value:"B",done:false}
    Object{value:"A",done:false}
    Object{value:"B",done:false}

}

6.什么时候用generator可以发挥强大的作用
eg:抽奖次数限制;
* 当前用户还可以抽奖5次;用户点击一次,抽奖变4次...1次,抽奖剩余逻辑,前端要做限制,服务端也要做;
好处:次数没有保存到全局变量中,通过初始化直接给generator传一个参数进去,让它不断的循环和业务的状态点,从而达到一个抽奖的次数限制和状态的变化;

    {
        //显示:抽奖逻辑这块;剩余5次,当点了抽奖按钮的时候,这个过程
        要执行抽奖的逻辑,随机过程,到哪个奖品上;还要显示当前剩余几次;
        //draw这个函数实现的是集体抽奖逻辑和当前剩余次数的显示;
        let draw =function(count){
            //具体抽奖逻辑
            //怎么计算当前还有多少次呢?
            --之前的做法:设一个全局的变量来保存当前的次数,这样非常不安全的;
              别人知道你的变量是什么,直接修改你的变量,都拦不住了;
              尽量少把数据存放在全局对象上,影响页面性能;
            console.info(`剩余${count}次`);
        };
        
        let residue =function*(count){
            //判断count是不是大于0,大于0还可以抽奖
            while(count>0){
                count--;
                //执行具体的抽奖逻辑;
                yield draw(count);
            
            }
        };
    
        let star =residue(5);
        let btn = document.createElement('button');
        btn.id='start';
        btn.textContent ='抽奖';
        document.body.appendChild(btn);
        document.getElementById('star').addEventListener('click',function(){
            star.next();
        },false);
        
    }

7.长轮询

  • 服务端的某一个数据状态定期的去变化,前端需要定时的去服务端取这个状态,因为http是无状态的连接,我们要怎么实时取得服务端的变化呢;
    • 两种方式:长轮询(之前做法通过定时器不断的访问一个接口;通过generator可以把长轮询的代码写的更加优雅,把跟业务逻辑相关的区分开)、websocket(浏览器兼容不好);
    {
        //长轮询;模拟ajax一个过程
        //这个ajax表示对接口的模拟;
        let ajax = functon* (){
            yield new Promise(function(resolve,reject){
                //模拟请求的耗时;用定时器模拟一下;
                //真实的环境中,setTimeout重写,写成真实的接口;在接口的成回调中,把
resolve写一下,就可以直接拿来用了;
                setTimeout(function(){
                    //接口成功返回了,执行resolve;比如最后返回的状态接口code:0;
                    resolve({code:0});
                    //resolve({code:1});会不断的轮询;
                },200);
            });
        };
        
        //轮询的过程;执行后端通信一次;
        let pull =function(){
            //对generator实例化;
            let generator = ajax();
            //取得当前generator的步骤,next相当于让generator进行了一次运行; 这个地方会
运行第一个的yield,返回一个promise实例,这个promise实例,对后端通信服务端接口进行一次连接,
查询一次;这里通过延时 200ms来表达200ms进行一次通信,然后接下一步;
            let step = generator.next();
            
        //value是promise实例,通过then异步操作,拿到d表示拿后端通信的数据,就是{code:0};        
            step.value.then(function(d){
                //判断如果数据拿到的是最新的;!=0就不是新的,要再一次的请求;
              if(d.code!=0){
                //每一秒钟请求一次;
                setTimeout(function(){
                    //查询中
                    console.info('wait');
                    pull();
                },1000);
              }else{
                //如果拿到最新数据,长轮询查询结束;直接把数据打出来;
                console.info(d);
              
              }  
            
            });
        };
        
        //相当于进行了一次轮询,因为{code:0}就查询了一次;
        pull();//Object{code:0}
        //{code:1}会每隔1200ms都是在输出wait,一直在进行一个长轮询的查询;
    }

相关文章

  • ECMAScript6--17.Generator

    1.Generator 基本概念异步编程的一种解决方案;Generator包含多个步骤,遇到每一个步骤的标志是yi...

网友评论

      本文标题:ECMAScript6--17.Generator

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