es6-async await 手写 前端进阶必备

共 4737字,需浏览 10分钟

 ·

2021-11-15 12:35

虽然上次的表白计划不了了之了,但我依然每天对她嘘寒问暖,我总相信,只要我对她好,总有一天我会感动她的。我也开始了所谓的舔狗之路......


一次和她的聊天中知道她喜欢吃大后街的一家早餐,但每天都起不来。然后我提出帮她带早餐,起初她还觉得有点不好意思稍稍有拒绝的意思,后来在我一系列劝说下答应了,她答应的那一刻,我高兴的像个孩子,那是我们除同学之外的第一个交集,也给我无限的遐想和期望。

大后街还是有点远的,为了防止面条软了,我也特意去买了辆自行车,还记得第一次买早餐的时候,我给自己定了6点的闹钟,兴奋、期待、紧张的我4点多就醒了,然后就毫无睡意了,脑子里一直在想等会应该和她说些啥,在哪里等她下来.....

给她带早餐的第六天,她说她来那个了,下来不了了,她的室友帮她下来拿的,那时候的我对这方面真的不懂,我们那的人感觉都太保守了,对这种东西比较隐晦,于是我百度了一下,然后叮嘱她多喝红糖水,多休息之类的话。聊着聊着我就怀着好奇问了一下她:“这大姨妈一个月来几次哇?”。这句话也让我成为了大学班上四年的笑话,至今还被他们提起.....

前言提示


各位掘友们,此篇文章需要从头认真往下阅读,不然无法理解下文我通过生成器*函数和yield实现的async awit。认真阅读包你搞透async 生成器 迭代器这些知识点。

整理知识点不易,如果大家学到了,帮我点赞关注,后续我会继续写进阶知识点。

迭代器、生成器、async

迭代器:迭代器是一种特殊对象,它具有一些专门为迭代过程设计的专有接口,所有的迭代器对象都有一个next()方法,每次调用都返回一个结果对象。结果对象有两个属性:一个是value,表示下一个将要返回的值;另一个是done,它是一个布尔类型的值,当没有更多可返回数据时返回true。迭代器还会保存一个内部指针,用来指向当前集合中值的位置,每调用一次next()方法,都会返回下一个可用的值

如何区分是否能迭代
   let arr=[1,2,3]     let str='123'     let obj={a:1,b:2}
for(var i of arr){ console.log('数组',i) }
for(var i of str){ console.log('字符串',i) }
for(var i of obj){ console.log('对象',i) }

打印结果如下图

说明:对象是不可迭代的

可以从原型去看一个类型是否支持迭代,以字符串为例

展开字符串的原型,会发现它存在Symbol(Symbol.iterator)这个属性,说明它是可以迭代的。

把这个属性用起来,再结合迭代器的描述,你或许能进一步理解迭代器。 
以 
let str1='舔狗的泪' 为例

手动实现一个迭代器效果   以对象为例

 var obj = {      a: 1,      b: 2,      c: 3,      [Symbol.iterator]() {        var index = 0;        let map = new Map([          ["a", 1],          ["b", 2],          ["c", 3],        ]);        return {          next() {            let mapEntries = [...map.entries()];//将它还原成二维数组            if (index < map.size) {              return {                value: mapEntries[index++],                done: false,              };            } else {              return { value: undefined, done: true };            }          },        };      },    };    let iter=obj[Symbol.iterator]()

测试下,同时会发现这个对象是能支持for of 的

遍历和迭代的区别

迭代:从目标源依次逐个抽取的方式来提取数据。目标源是有序,连续
遍历:只要能够循环数据,并不需要有序。
因为对象循环不是有序的,所有它无法迭代,但是Map是可以支持迭代的。

生成器

函数前带 * 表示生成器  用yield去产出它的值

function * test(){      yield 1      yield 2      yield 3    }  var iter=test()  iter.next()  //输出 {value:1,done:false}
iter也是可以通过for of循环,这里不演示了

注意:每次调用next,他都会走到一个yield,下面代码不会打印log

  function * test(){      console.log('舔狗的泪')      yield 1      yield 2      yield 3    }  var iter=test()  //要调用iter.next()才会走console.log
生成器的yield 换成return 看看区别:


基于yield去改造刚才让对象能够迭代的方法
var obj = {        a: 1,        b: 2,        c: 3,        [Symbol.iterator]:function * () {          var index = 0;          let map = new Map([            ['a', 1],            ['b', 2],            ['c', 3]          ]);          let mapEntries = [...map.entries()]; //将它还原成二维数组          while(index            yield mapEntries[index++]          }        }      };      let iter = obj[Symbol.iterator]();
对next方法传参,看看yield丑陋的一面,async前世
  function* test() {        let value1 = yield 1;        console.log('value1',value1);        let value2 = yield 2;        console.log('value2',value2);        let value3 = yield 3;        console.log('value3',value3);      }      var iter=test()      iter.next('one')      iter.next('two')      iter.next('three')      iter.next('')

结果分析:next里面的值会赋给上一次yield 的值 。
站在开发者角度更期望 value1 打印的值就是1。async await它来了


async await基本操作

async await常见用法:let x=await 异步请求
看看它的其他用法,直接看图说话:

  function b() {        return new Promise(resolve => {          setTimeout(() => resolve(1), 1000);        });      }      async function a() {        let value = await b();        console.log(value);      }      a();      //1秒后打印1
   function b(){        return 1      }      async function a() {        let value = await b();        console.log(value);      }      a();      //打印1
function b() {        let c = 1;      }      async function a() {        let a = await b();        console.log(a);      }      a();       //打印undefined

基于* yield实现一个async

以下面例子去实现

let num=1      //b函数只为模拟一个axios      function b() {        return new Promise(resolve => {          setTimeout(() => resolve(num++), 1000);        });      }      async function a() {        let value1 = await b();        let value2 = await b();        let value3 = await b();        console.log(value1,value2,value3);        return value3      }      let promise =a();      //3秒后打印 1,2,3
基于生成器 递归实现,需要先看上面的对next方法传参,你才能明白下图
 let num = 1;      function b() {        return new Promise(resolve => {          setTimeout(() => resolve(num++), 1000);        });      }      function* a() {        let value1 = yield b();        let value2 = yield b();        let value3 = yield b();        console.log(value1, value2, value3);        return value3      }      function Co(iter) {      //因为async方法内部包裹的就是Promise,所以这里也return一个Promise        return new Promise((resolve, reject) => {          let next = function (data) {            let { value, done } = iter.next(data);            if (done) {              resolve(data);            } else {            //兼容b函数是一个非异步操作            value instanceof Promise?              value.then(val => {                next(val);              }, reject):next(value);            }          };          next();        });      }     let promise = Co(a());
个人理解及总结

迭代器:它的原型上面存在Symbol(Symbol.iterator),它可以被for of 循环
生成器:* 配合yield 的一个函数
如果你搞懂了生成器函数,基于它实现async await就变得很容易了。
目前把es6里面的class Map Set Promise底层实现都写完了

源自:https://juejin.cn/post/7029100142208745503

声明:文章著作权归作者所有,如有侵权,请联系小编删除。

感谢 · 转发欢迎大家留言


浏览 32
点赞
评论
收藏
分享

手机扫一扫分享

分享
举报
评论
图片
表情
推荐
点赞
评论
收藏
分享

手机扫一扫分享

分享
举报