聊聊generator生成器

·  阅读 255

聊聊generator生成器

一、创建一个生成器


function * gen(){};
function *gen(){};
function* gen(){};

复制代码

上面就是生成器的基本写法,在函数的申明时加一个*号;如果调用这个生成器函数;就会返回一个迭代器;所谓迭代器就是一个具有 next的属性,并且这个属性的值是一个函数的对象;

二、迭代器

当我们将生成器调用后会返回一个迭代器,迭代器就是一个对象,这个对象中有一个next的方法,调用这个方法后,会收到一个类似{value:值,done:结束状态}的对象;表示得到的值,和是否结束迭代;

function *gen(){
  yield 1;
  yield 2;
};

 let itor = gen();
 itor.next()  // {value:1 , done :false}
 itor.next()  // {value:2 , done :false}
 itor.next()  // {value:undefined , done :true}
复制代码

上面的代码表示迭代器经过三次调用之后,结束了;因为done已经是 true的状态;表示已经结束了;

yield是一个关键字,表示程序到这里会是一个暂停的状态;当第一次调用next()后指针移动向第一个yield右侧的内容;并且之后的代码会执行,next()返回的value就是第一个yield右侧的值;但是yield左侧和后面的内容不会执行,第一次的next()传入的任何参数也都没有用;第二次调用next()函数,先执行第一个yield左侧的内容和后面的内容,并且指针移动向第二个yield右侧,并将右侧的内容返回给value;依次顺序执行下去;

三、实现一个async函数;

利用gen函数实现一个await 和 async的效果;

如何实现一个async函数的效果,我们知道await 可以阻塞后续代码的执行,只有前一个await有结果了之后,后面的才会执行,因此我们可以也通过控制执行next函数的时机,然后达到这样的效果;看一下代码;



let getValue = function (url) {
  return new Promise(resolve => {
    console.log(url);
    setTimeout(() => {
      resolve(url);
    }, 1000)
  })
}

// 先定义一个异步函数;
function* gen () {
  yield getValue('1')
  yield getValue('2')
  yield getValue('3')
  yield getValue('4')
  yield getValue('5')
}


复制代码

在上面的代码的基础上,我们可以思考一下,如果实现,一个等一个这样的效果;因为按照正常的过程,我们需要一个一个调用next函数,获得结果;因此在何时调用next函数就是问题的关键;如果要实现一个等一个的效果,我们就需要做到在上一个getValue()结果回来的时候调用;因此可以实现下面的代码;

function co (gen) {
  let itor = gen();
  function next (data) {
    let res = itor.next(data);
    if (res.done) {
      return res.value;
    }
    res.value.then(data => {
      next(data)
    })
  }

  next()
}


co(gen)

复制代码

其实本质上async以及await的原理,就是gen()函数加上一个异步的调度器;在这里可以理解为这个co函数;

分类:
前端
标签:
收藏成功!
已添加到「」, 点击更改