开篇: 以下为我的理解 感觉有帮助的小伙伴点个赞 有啥问题可以评论区一起探讨
阮一峰老师的文章曾经说过async
函数完全可以看作多个异步操作,包装成的一个 Promise 对象,而await
命令就是内部then
命令的语法糖。其中也提到了async和await的原理就是通过generate生成器和iterator迭代器实现的
在此之前我们应该先去了解一下generate生成器和iterator迭代器
我理解的generate生成器它主要作用就是允许我们对数据进行分段处理,而不是一次性把所有数据全部加载完毕,在实际业务中我们很少或根本就没有用上,因为如果是一些不怎么占用内存的数据也没必要使用生成器,他主要用来处理一些比较大的文件流,或者成千上万条数据时比较有用,分段执行,先拿取要最先使用的数据,再慢慢继续执行,
iterator迭代器
js中在原型中存在Symbol.iterator属性的都是可迭代对象,可迭代对象最明显的特征就是可以通过
for of 来进行遍历迭代
HTMLCollection,NodeList ,Map ,Set,String,Array,Arguments等都是可迭代对象
我来举一个更生动的例子
const arr = [1,2,3,4]
const iterator = arr[Symbol.iterator]()
iterator.next()
更加形象了吧,当然symbol.iterator也可以手动加到原型上去,比如将对象变成可迭代的,这个感兴趣的小伙伴可以去试试
生成器和迭代器就讲到这吧,具体的小伙伴可以网上找些视频资料啥的研究研究,接下来才是正题
话不多说,直接附代码+注释:
/**
* 在此代码中
* 我们以test模拟接口
* 以fn为我们的代码逻辑执行函数
* 以gen为js为我们封装的async 和 await
*/
function test1(str){
return new Promise((res,rej)=>{
setTimeout(()=>{
res(str)
},3000)
})
}
function test2(str){
return new Promise((res,rej)=>{
setTimeout(()=>{
res(str)
},1000)
})
}
function test3(str){
return new Promise((res,rej)=>{
setTimeout(()=>{
res(str)
},2000)
})
}
// async 可以正常执行
// async function fn(){
// let res1 = await test1('3,1')
// console.log(res1);
// let res2 = await test2('2,2')
// console.log(res2);
// let res3 = await test3('1,3')
// console.log(res3);
// }
//假如:js将拥有async前缀的函数改成 generate await 改成yield
function *fn(a,b,c){
let res1 = yield test1(a) // res1的值为下一次next接收的值
console.log(res1);
let res2 = yield test2(b)
console.log(res2);
let res3 = yield test3(c)
console.log(res3);
return res3 //最后一个next return出去
}
//并且内部还封装了一个函数
function gen(fn){
const iterator = fn('3,1','2,2','1,3') //生成迭代器
let res;
const p = new Promise((r)=>{ // 因为使用async为前缀的函数最后都是一个promise
res = r; // p就是最后返回的promise
})
// 去遍历每一个迭代对象
function recursion(val = undefined){
/**
* 第一次调用执行test1函数 传值就无所谓了,因为第一次本来就是第一个yield,第一个yield的返回
* 值是根据下一次next传值定义的,返回done,value,done为false,则执行下面的判断是否为promise,
* 如果不是则没有异步,直接调用下一次的next,否则等异步执行完成后调用
*
* 第二次执行recursion,再调用next并且传递第一次执行返回的值,这样res1就能接收到返回的结果了
* 第一个yield res1 返回值为 3,1
* 执行test2函数,获取到他返回的done和value,也是false,则继续判断是否为promise,并且把value交给第三次next函数
* 第二个yield res2 返回值为 2,2
* 第三次执行recursion,基本同上
* 第三个yield res3 返回值3,1
*
* 第四次执行recursion函数,调用next函数,他发现没有yield了,则只是打印了一下res3的值,返回的done为true,value为
* return的res3,done为true,则调用res这个成功的函数返回出去
* 整体流程就这样
* 不过需要注意的是 每一次调用next,他执行的是要执行到yield哪一行到上一次yield的下面那一行
* 例如
* 第一次next执行的是41行
* 第二次next执行的是42,43行
* 以此类推
*
*/
const {done,value} = iterator.next(val) //执行yield
if(done){
return res(value)
}
if(value instanceof Promise){
value.then((res)=>{
recursion(res)
})
}else{
recursion(value)
}
}
recursion()
return p
}
gen(fn).then((res)=>{
console.log(res); //该then 就可以当作是fn函数的返回值
})