async是Generator函数的语法糖,比起Generator更加具有语义。定义一个Generator函数需要类似于如下方式:
function * test(){ yield 1; yield 2; return 3}var a = test() //不会执行a.next();a.next();复制代码
定义async函数只需要:
async function test(){ var a = await 1 var b = await 2 return b}test().then((res)=>{ // res为test函数的返回值。可见async会返回一个Promise对象})复制代码
在实际使用中await后面实际上更多的是一个异步函数,例如一个promise对象的操作结果
// 模拟接口Afunction getA(){ return new Promise((resolve,reject)=>{ setTimeout(()=>{ let res = Math.random() if(res>0.5){ resolve(res) } else { reject(res) } },2000) })}// 模拟接口Bfunction getB(){ return new Promise((resolve,reject)=>{ setTimeout(()=>{ let res = Math.random() if(res>0.5){ resolve(res) } else { reject(res) } },2000) })}async function print(){ let a = await getA().catch((error)=>{ console.log(error) }) let b = await getB() return [a,b]}print().then((res)=>{ console.log('成功',res)}).catch((err)=>{ console.log('错误',err)})复制代码
上述print函数a变量值需要等到getA执行完毕才能获得。getB需要await getA()执行完毕才会执行。所以print的执行时间是getA和getB的和。这就是所谓的同步方式执行异步函数。 不过使用同步方式执行异步函数的方式也有局限性。
- 如果有耗时任务将会阻塞。 假如getA需要大约耗时10s,则getB不得不等到getA执行完毕。
- 如果async内有一个函数发生错误,则函数不再执行,错误将直接被catch捕捉,例如getA状态为reject.则test().catch((error)=>{})将捕捉错误,getB不会执行。如果需要getB继续执行,需要添加try...catch:
async function print(){ try{ let a = await getA() }catch(error){ } let b = await getB() return [a,b]}复制代码
async使得异步操作流程更加有序化,在promise中
getA()getB()复制代码
虽然getA定义在前面,但却不一定会先于getB返回值,这样在实际开发中可能给我们造成麻烦,因为实际开发中数据是由依赖的和有先后之分的。所以为了有序化,单纯使用promise我们不得不使用如下类似代码:
getA().then(()=>{ return getB()}).then(()=>{ return getC()})...复制代码
写的越多,代码就不具有可读性,也不利于调试。使用上述的async+await可以很爽地写代码啦.
async function getAsyncData(){ let a = await getA(); let b = await getB()}getAsyncData().then(()=>{ })复制代码
我们把异步操作的函数(例如ajax,读取文件等)定义在async函数内,配合await可以使得异步操作有序化,即先getA再执行getB.