我们都知道async/await是基于Promise 的语法糖,他可以阻塞我们的异步操作来让我们更好的控制我们的异步任务,那么async await是怎么实现的呢,上一章节我们讲解过生成器,生成器每次执行next后就会停留在下一次yield上,这样就是不是很像我们await的阻塞,那么我们是不是就可以理解为我们的async、await其实是可以通过生成器来实现的,我们看下面这一段函数
const test=()=>new Promise((resolve,reject)=>
setTimeout(()=>{
resolve('test')
},1000))
async function func(){
const data= await test()
console.log(data);
const data= await test()
console.log(data);
}
这一段函数就可以使用生成器来模拟实现,模拟成下面这一段。
function* func(){
const data= yield test()
console.log(data);
const data= yield test()
console.log(data);
}
但是呢,生成器无法自动执行,一定要执行生成迭代器后手动调用next才能执行,我们可以手动执行一下上面这个方法
const it=func();
const p=it.next();//返回{value:Promise,done:false}
p.value.then(res=>{
console.log(res);
const p2=it.next();
p2.value.then(res=>{
console.log(res);
})
})
是不是有一种回调地狱的感觉,如果我们要yield test()直接返回resolve的值,首先执行到yield test()时,值是还没有确定的,什么时候会确定呢,就是执行下一次next方法时,通过传参数next(val)的方式来确定值,什么意思呢,看下面这段代码
function* func(){
const ans=yield test();
console.log(ans);
const ans2=yield test();
console.log(ans2);
}
const it=func();
const p=it.next();//返回{value:Promise,done:false},这是ans并没有获取到resolve的值
p.value.then(res=>{
console.log(res);
const p2=it.next(res); //这一步时上面代码中的ans才会被确定值为res;
p2.value.then(res=>{
console.log(res);
})
})
上面代码还是手动执行的,且我们最后一个yield是拿不到值的那么我们怎么修改才能拿到值呢,很简单,只要稍微改一点就行了,改为一个简单的递归即可。
function autoStart(generator){
const gen=generator();//执行生成器函数
function _next(val){
const p=gen.next(val);
if(p.done) return p.value; //递归结束
p.then(res=>{
_next(res); //递归
})
}
_next();
}
auto(func);
上面我们就基本实现了一个简单的async/await,然后我们在一步步优化,首先async函数是返回的Promise,其次还要进行异常处理,所以上面我们就要改成返回Promise并对其异常进行处理
function autoStart(generator){
const gen=generator();
function _next(val){
return new Promise((resolve,reject)=>{
try{
var p=gen.next(val);
if(p.done) resolve(p.value);
}catch(err){
reject(err);
}
//防止p.value为基本类型的情况
Promise.resolve(p.value).then(res=>{
_next(res);
})
})
}
_next();
}
最后我们使用这段代码来尝试一下
完整demo
const test =(data)=>new Promise((resolve,reject)=>{
setTimeout(()=>{
resolve(data);
})
})
function autoStart(generator){
const gen=generator();
function _next(val){
return new Promise((resolve,reject)=>{
try{
var p=gen.next(val);
if(p.done) resolve(p.value);
}catch(err){
reject(err);
}
//防止p.value为基本类型的情况
Promise.resolve(p.value).then(res=>{
_next(res);
})
})
}
_next();
}
function* generator(){
const data=yield test(1);
console.log(data);
console.log(2);
const data2=yield 3;
console.log(data2)
console.log(4);
}
autoStart(generator);
// 1
// 2
// 3
// 4
//完美输出
参考文章
手写async await的最简实现(20行)
9k字 | Promise/async/Generator实现原理解析