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
声明:文章著作权归作者所有,如有侵权,请联系小编删除。