手写async await
async await是generator函数的语法糖,主要用到了generator函数的yield来暂停,next来继续执行
async 写法
async function getData()
const data1 = await getData1();
console.log('data1:',data1);
const data2 = await getData2();
console.log('data2:',data2);
return data2;
}
转化为 generator函数
const getData = () => new Promise(resolve => setTimeout(() => resolve("data"), 1000))
function* getDataG(){
const data1 = yield getData()
console.log('data:', data1);
const data2 = yield getData()
console.log('data2:', data2);
return data2;
}
generator函数需要通过next来执行里面函数体,通过yield来暂停等待执行,这个函数不会自己执行,所以需要写一个函数调用next来帮助执行
asyncGenerator函数
这个函数的作用传进去一个generator函数,然后函数自动执行next
function asyncGenerator(generatorFunc) {
// 返回一个new Promise
return new Promise((resolve, reject) => {
let gen = generatorFunc();
// 然后定义一个setp() 接受一个参数nextF函数
function setp(nextF) {
// nextF 里面定义一个next变量
let next;
// try catch 执行nextF 成功的话next接收函数返回值 失败则return reject
try {
next = nextF();
} catch (err) {
return reject(err);
}
// 然后判断next的done的值 为true 直接return resolve
if (next.done) {
return resolve(next.value);
}
// Promise.resolve(next.value) 这样可以不管next.value是不是promise 都可以使用then
Promise.resolve(next.value).then(
(res) => {
// 继续执行 gen.next(next.value))递归下去
setp(function () {
return gen.next(res);
});
},
(err) => {
// 失败则使用gen.throw 方法
setp(function () {
return gen.throw(err);
});
}
);
}
// 定义完然后执行setp()
setp(function () {
return gen.next();
});
});
}
函数执行解析
-
执行传进去的
generatorFunc函数赋值为变量gen, 函数底部执行gen.next(),gen.next()函数,执行函数体中的代码,然后遇到yield暂停执行,yield的右边函数值赋值给变量next,next的值{ value, done }的结构,next.done为false继续执行,使用Promise的resolve方法统一当异步数据处理,等待next.value异步then完成得到res并执行gen.next(res)。 -
执行
gen.next(res),res变量赋值给yield左边的变量,继续执行函数体中的代码,遇到yield暂停执行,yield的右边函数值赋值给变量next,next.done为false继续执行,使用Promise的resolve方法统一当异步数据处理,等待next.value异步then完成得到res并执行gen.next(res)。 -
next.done为false的话就一直重复第二个步骤,递归下去,直到next.donne为true就直接返回next.value,函数终止
ps:async使用异步代码也可以使用同步代码的方式编写,主要是因为函数体一遇到yield就需要等待yield右边方代码执行完毕才会继续执行。
函数步骤解析
-
第一次使用
next()next()返回值赋值给变量next,执行下方函数体中的代码,yield关键前的代码,执行yield右边的代码``getData();并使用then等待后将结果res,next.done为false调用第二次next(res)这一步变量data1`并未赋值ps: 变量
next保存留给下次调用next()的时候传入当参数console.log('start'); getData(); -
第二次使用
next()上一步中调用
next(res)函数,执行下方函数体,res参数赋值给yield左边的变量,data1赋值成功,返回值赋值给变量next,const data1 // data1 = res console.log('data:', data1); getData()next.done为false,调用第三次next(res)直到遇到
yield暂停执行,执行yield右边的代码getData();并使用then等待后将结果res,调用第三次next(res),这一步变量data2并未赋值 -
第三次使用
next()上一步中调用
next(res)函数,执行下方函数体,res参数赋值给yield左边的变量,data2赋值成功,返回值赋值给变量nextconst data2 = // data2 = res console.log('data2:', data2); return data2;next.done为true,直接返回next.value,函数终止