1、async await由来
众所周知,async以及await的出现只要是为了解决promise以及xhr等回调地狱的问题的,使用的办法就是相当于平时的同步函数一样,要点:
- await必须用在async函数里面
- 返回值是一个promise(fulfilled或者rejected)
2、generator函数
以下是一个典型的generator函数,函数名前有个*号,里面的yield归还控制权 给主程序,这就是js里面的协程。从中可以看到两点
- 每次调用next函数,则会返回一个对象,对象有两个属性value以及done,value是每个yield后面的返回值,done代表该函数是否已经执行结束了。
- 每次在next函数里面传入的值会被对应的前一个yield接收,比如里面的a,b
function * myGenerator(){
const a = yield 1;
const b = yield 2;
console.log("my a:",a)
// my a: a
console.log("my b:",b)
// my b: b
return "over"
}
let myGen = myGenerator()
console.log(myGen.next())
// { value: 1, done: false }
console.log(myGen.next("a"))
// { value: 2, done: false }
console.log(myGen.next("b"))
// { value: 'over', done: true }
3、async\await - generator的语法糖
在generator函数中,yield会让出控制权,然后后面的代码将会不会执行,直到下一次调用next交还控制权才会继续执行,那么这个场景是否有见过呢? 由此可以想到,在我们的async函数中await后面返回的promise变为rejected或者fulfilled才能继续执行下面的函数,那么这两种情况一对比,那么就可以得出:如果要是想实现async\await,就得在promise.then或者promise.catch里面继续调用next函数,调用next可以交还控制权继续执行后面的代码
4、async函数的实现就是将Generator函数和自动执行器包装在一个函数中,这个自动执行器实现如下:(抄载于阮一峰)
/**
*
* @param {*} genF 一个gerneator函数
* @returns 一个promise对象
*/
function spawn(genF){
// 每个async函数的返回值都是一个promise对象
return new Promise(function(resolve,reject){
var gen = genF();
function step(nextF){
// 1、获取第一个yield的返回值
try{
var next = nextF()
}catch(e){
return reject(e)
}
// 如果已经结束,那么就直接resolve该promise
if(next.done){
return resolve(next.value)
}
// next.value代表指的是上一个yield的返回值,then是代表next.value代表promise已经改变了状态
// 也就是说在这个返回值完成之后再调用next归还执行权给他,运行下一步代码
Promise.resolve(next.value).then(
function(v){
step(function(){return gen.next(v)})
},
function(err){
// 抛出错误,第一个try那里接收
step(function(){return gen.throw(err)})
}
)
}
step(function(){gen.next(undefined)})
})
}