上一篇我们说到promise,当然除了promise对象我们ES7也推出了async await新的异步任务解决方案,这篇文章我们就一起认识一下async await,以及它出现的原因。
ES7新特性 async await
为什么有async await?
大家都知道,对于异步任务的解决方案我们已经有了Promise的解决方案了,那为什么我们还需要async await这种解决方案呢?
其实原因非常简单,当代码中存在大量的异步请求的时候,Promise的链式调用看起来就没那么直观了,当满屏幕充斥着大量的.then方法时,相信大家也会晕头转向的,这就是async await这个语法糖出现的原因。
async await需要注意什么?
- async和await是一对好基友,他们两个缺一不可,算是Promise的进化版本
- async和await也是为Promise服务的
- async声明的必须是一个function,不然await会报错
- await是使用在async声明的函数内部的
async的本质
- async本质是它声明的函数会返回一个Promise
async function(){
return ("i am Promise")
}()
这个函数的返回为Promise(<resolved> : "i am Promise")
这个会自动的解析成Promise.resolve("i am Promise")
等同于下面这种写法
(async function () {
return Promise.resolve("i am Promise");
})()
所以如果当你想用async声明函数的返回值时,可以用变量存储这个async声明的函数
然后通过链式调用.then()来拿到所返回的Promise传来的值
const asyncFun = async function(){
return Promise.resolve("i am Promise")
}
asyncFun.then((result)=>{
console.log(result)
})
结果显示输出 "i am Promise"
await的使用
-
await字面意思就是"等一小会儿"的意思,他可以提供等待异步返回的能力,只要await声明的异步任务还没有返回,后面的程序将不会执行
-
await一定是在等待一个Promise对象的返回,如果await等待返回的对象不是Promise的话,它是起不到等待作用的
看一下这个例子
const asyncFun = function(){
let result = async setTimeout(()=>{
console.log("等待1秒")
},1000)
console.log("猜猜是谁先执行")
return result
}
asyncFun.then(result=> {
console.log("输出",result)
})
输出结果如下:
猜猜是谁先执行
输出 1
等待1秒
setTimeout是异步可是并没有等待它执行完毕再向后执行,原因是await必须等待一个Promise的返回才能起作用,这个用于异步任务调用的时候。
异步任务调用时Promise和async await的不同
假定现在有两个异步函数
asyncFunBefore = ()=>{
return new Promise((resolve,reject)=>{
setTimeout(()=>{
resolve('延迟1秒')
},1000)
})
}
asyncFunAfter = ()=>{
return new Promise((resolve,reject)=>{
setTimeout(()=>{
resolve('延迟2秒')
},2000)
})
}
比如我现在需要先延迟1秒,再延迟2秒,再延迟1秒再输出结果,那么Promise的写法如下:
(这里的参数我用不同的序号标识一下,这样大家分辨的时候会更直观一点)
asyncFunBefore()
.then(result =>{
console.log(result)
return asyncFunAfter()
}).then(result2 =>{
console.log(result2)
return asyncFunBefore()
}).then(result3 =>{
console.log(result3)
console.log('完成')
}).catch(error =>{
console.log(error)
})
这样看起来非常的不直观,如果调用方法多了的话会更加难以理解
接下来我们改造成async await的写法试试:
(async ()=>{
const result = await asyncFunBefore()
console.log(result)
const result2 = await asyncFunAfter()
console.log(result2)
const result3 = await asyncFunBefore()
console.log(result3)
console.log('完成')
})()
这里我们是不是没展示如何捕获错误,一般我们用try catch方法来做,具体如下:
(async ()=>{
try{
const result = await asyncFunBefore()
console.log(result)
const result2 = await asyncFunAfter()
console.log(result2)
const result3 = await asyncFunBefore()
console.log(result3)
console.log('完成')
}catch(e){
console.log(e) //这里用来捕获错误
}
})()
通常代码中不会存在太多的try catch,如果try catch太多的话,可能代码需要重构一下
async await中断
- 首先明确一下,Promise一旦状态改变是无法再被终止的
- 这里的中止是将方法挂起,并没有取消Promise的请求
- 直接在async声明的函数中返回一个值即可,
null,空或者false都是可以的
代码如下所示:
let i = 6
const asyncFun = ()=>{
const result = await asyncFunBefore()
console.log(result)
const result2 = await asyncFunAfter()
console.log(result2)
const result3 = await asyncFunBefore()
if(i > 5){
return '从这里退出,后边不会执行'
}
console.log(result3)
console.log('完成')
}
asyncFun.then(result=> {
console.log(result)
}).catch(error=> {
console.log(error)
})
这里会输出:
从这里退出,后边不会执行
原因是我们之前说了,async声明的函数本质是返回一个Promise,
所以在这里return就相当于是Promise.resolve('从这里退出,后边不会执行')
这个时候状态发生改变了,会直接去走.then()中的代码
这样就可以手动终端async中的后续代码,但是只是暂时挂起,并不是取消请求了