• wordpress CMS主题:ssmay主题 wordpress CMS主题:ssmay主题
  • 首页 > 前端开发 > 迭代器,生成器(generator)和Promise的“微妙”关系

    迭代器,生成器(generator)和Promise的“微妙”关系

    作者: 分类:前端开发 点击: 412 次
    wordpress CMS主题:ssmay主题

      扫描下面的二维码,“关注”我的百家号。

      需要Promise源码版的朋友:传送链接

      本文主要讲述(iterator)和生成器*/yield之间的联系和各自的用法,以及生成器的高配版本async/await的使用。

      大纲:

      • 迭代器(iterator)
      • 生成器 */yield
      • 异步版生成器 async/await

      迭代器(iterator)

      先瞅瞅“迭代”,这个词是什么意思呢?每一次“过程”的重复,称之为迭代。不过迭代是会保留结果的,也就说每次都是以上一次迭代的结果为基准,开始下一次的迭代。举个例子,迭代这个词经常出现在产品开发之中,每个周期都会有产品的迭代开发,但是不可能每次都是从零开始做产品,肯定是基于上一版本的产品进行开发,也就是进行迭代。

      从中我们可以整理出关于迭代的两个关键点:

      • 过程是重复的
      • 返回上一次的迭代结果

      那么JS中的“迭代器”是个怎样的概念呢?

      查看MDN中的概念:传送地址

      个人观点:JS中的迭代器,就是一个数组对象,不断地调用next重复获取过程,然后每次都返回一个结果。等到没有东西可返回了,就终止。因此next的返回对象有两个属性donevaluedone表示是否结束了,value表示当前迭代的结果。当donetrue的时候,表示迭代已结束,这时候是没有返回结果的也就是没有value这个属性。

      然而迭代器是有一系列的规范的:

      查看MDN中的概念:传送地址

      迭代器

      • 关于迭代器,就是我们上面讨论的next方法,返回donevaluedone:true时可以省略)两个参数。
      function iteratorFunc(){
          let arr=[...arguments]
          let nIndex=0
          return {
              next:()=>{
                  return nIndex<arr.length?
                  {value:arr[nIndex++],done:false}:{done:true}
              }
          }
      }
      let a=iteratorFunc(1,2,3)
      console.log(a.next())//{done:false,value:1}
      console.log(a.next())//{done:false,value:2}
      console.log(a.next())//{done:false,value:3}
      console.log(a.next())//{done:true}
      

      可迭代“对象”

      • 关于可迭代“对象”,我们需要再对象上实现@@iterator方法,也就是[Symbol.iterator],返回一个自定义的迭代方法,以表明这个对象是可以迭代的。有些JS内置的对象就是可迭代的,比如String,Array。

      自带的可迭代事例:

      let str="我是欢乐的迭代器"
      let b=str[Symbol.iterator]()
      console.log(b.next())//{value: "我", done: false}
      console.log(b.next())//{value: "是", done: false}
      console.log(b.next())//{value: "欢", done: false}
      

      有没有很神奇啊!用了这么久的字符串,居然还有这种操作。他的效果等同于上方的自定义迭代方法。那么我们来写个自定义的迭代方法:

      str[Symbol.iterator] = function() {
          return { // this is the iterator object, returning a single element, the string "bye"
            next: function() {
              this._index += 2
              if (this._index<str.length) {
                return { value: str[this._index], done: false };
              } else {
                return { done: true };
              }
            },
            _index:-2
          };
      };
      let c=str[Symbol.iterator]()
      console.log(c.next())//{value: "我", done: false}
      console.log(c.next())//{value: "欢", done: false}
      console.log(c.next())//{value: "的", done: false}
      console.log(c.next())//{value: "代", done: false}
      console.log(c.next())//{done: true}
      

      这里我写的迭代器是返回一个隔一个字符。运行成功~yeah~

      生成器(generator)

      感觉写迭代器还是很绕呢,于是出现了生成器(generator),专门帮我们生成迭代器的存在。

      function * g(){}
      let it= g()
      console.log(it.next())//{value: undefined, done: true}
      

      看到熟悉的结构没有!{value: undefined, done: true},不过我们没有值。这个时候要向大家推荐*的好基友yield,一个yield对应一个next的值。

      我们改写下上方的字符串的迭代器:

      str[Symbol.iterator]= function * (){
          let index=-2;
          while(index<this.length){
              index += 2
              yield this[index]
          }
      }
      let kk=str[Symbol.iterator]()
      console.log(kk.next())//{value: "我", done: false}
      console.log(kk.next())//{value: "欢", done: false}
      console.log(kk.next())//{value: "的", done: false}
      console.log(kk.next())//{value: "代", done: false}
      

      是不是方便了很多。

      我们带着几个疑问来看看生成器:

      • yield的返回值是啥?
      • 执行顺序?

      实例代码:

      function * gy(){
          console.log("zero")
          let fisrt=yield "first"
          console.log("fisrt",fisrt)
          let second=yield "first"
          console.log("second",second)
      }
      let ity= gy()
      

      第一次执行ity.next(),只打印了zero

      第二次执行ity.next(),只打印了first undefined

      第三次执行ity.next("third"),只打印了second third

      由此可见每次的next都止步于yield,就不再执行下去了。yield每次返回的都是当前ity.next(value)value值。

      async/await

      我们来看看对于Promise这个对象的迭代器,我们该怎么处理。也就是每个迭代器都是异步的。

      function setTime(value,id){
          return new Promise((r,j)=>setTimeout(() => {
              console.log(value)
              r(id)
          }, 10))
      }
      function *a(){
          let r1 = yield setTime("first",1)
          console.log(r1)
          let r2 =yield setTime("second",2)
          console.log(r2)
          let r3 =yield setTime("third",3)
          console.log(r3)
      }
      let k=a();
      new Promise((resolve,reject)=>{
          function next(data){
              let {value,done}=k.next(data)
              //k.next()返回一个promise,因此可以then
              if(!done){
                  value.then((data)=>{
                      console.log(data)
                      next(data)
                  })
              }
          }
          next();
      })
      

      因为每个都是异步的,所以需要我们二次处理,这个时候async/await就可以出场了。只需要把*/yield无缝改成async/await即可。

      async function a() {
          let r1 = await setTime("first",1)
          console.log(r1)
          let r2 = await setTime("second",2)
          console.log(r2)
          let r3 = await setTime("third",3)
          console.log(r3)
      }
      a()
      


      欢迎“关注”我的百家号。

      头条二维码
      加入我的QQ群
      头条二维码
      关注我的百家号

    文章作者:sunny
    本文地址:http://wanlimm.com/77202006218423.html
    版权所有 © 转载时必须以链接形式注明作者和原始出处!

    上一篇:
    下一篇:
    wordpress CMS主题:ssmay主题

    或许你会感兴趣的文章:

    发表评论

    电子邮件地址不会被公开。 必填项已用*标注

    This site uses Akismet to reduce spam. Learn how your comment data is processed.