Skip to content

Latest commit

 

History

History
143 lines (137 loc) · 4.14 KB

File metadata and controls

143 lines (137 loc) · 4.14 KB

Generator

Generator是一种异步编程的解决方案,异步编程早期使用回调之后Promise也可以解决这个问题,而Generator也是用来解决这个问个的,但是相对于Promise会更高级一点。Generator返回的就是一个Iterator接口。

提示: index.js:126 Uncaught ReferenceError: regeneratorRuntime is not defined 需要: import 'babel-polyfill'

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

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
 }

Generator最好是用在状态机,是JS编程中比较高级的用法,比如我们需要有a b c三种状态去描述一个事物,也就是这个事务只存在3种状态a-b b-c c-a 总之就是三种循环,永远跑不出第四种状态,用Generator函数去处理这种状态机是特别适用的

{
  let state = function* (){
    while(1){
      yield 'A';
      yield 'B';
      yield 'C';
    }
  }
  let status = state();
  /*
    console.log(status.next()); //A
    console.log(status.next()); //B
    console.log(status.next()); //C
    console.log(status.next()); //A
    console.log(status.next()); //B  
  */
  setInterval(function(){
    console.log(status.next());
  },1000);
}
{
  //async await这种写法并不是一种新的写法,只是Generator的一种语法糖
  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());
}

通过Generator实现抽奖

{
  let draw = function(count){
    //具体抽奖逻辑
    console.log(`剩余${count}次`);
  }
  let residue = function* (count){
    while(count > 0){
      count--;
      yield draw(count);
    }
  }
  let start = residue(5);
  let btn = document.createElement('button');
  btn.id = 'start';
  btn.textContent = '抽奖';
  document.body.appendChild(btn);
  document.getElementById('start').addEventListener('click',function(){
    start.next();
  },false);
}

如果服务端的某个数据状态定期的去变化,那么前端需要定时的去服务端取这个状态,因为http是无状态的链接,如果要实时的去取服务端的这种变化有两种方法,一个是长轮询,一个是通过websocket,websocket浏览器兼容性不好,因此长轮询还是一个普遍的用法 一种做法是通过定时器,不断的去访问接口 第二种是使用Generator

{
  //长轮询
  let ajax = function* (){
    yield new Promise(function(resolve,reject){
      //这里模拟api成功执行后 执行resolve,比如下面的{code:0},意思是返回接口成功执行后的数据
      setTimeout(function(){
        resolve({code:1})
      },200);
    });
  }

  let pull = function(){
    let generator = ajax();
    let step = generator.next(); //会返回一个promise对象实例,会对服务器端接口进行一次查询链接,上面采用setTimeout200毫秒来模拟
    //这个value就是代表了 promise实例,then是异步操作
    step.value.then(function(d){ //这个d是后端通讯的数据,这里就是上面的{code:0}
      if (d.code != 0) {
        //如果不等于 不是最新的数据,我们让每1秒钟执行一次
        setTimeout(function(){
          console.info('wait');
          pull();
        },1000)
      }else{
        //如果拿到最新数据,这里就打印出来
        console.log(d);
      }
    })
  }
  pull()
}