一、async/await是什么?
async用于申明一个function是异步的;
而await则可以认为是 async await的简写形式,是等待一个异步方法执行完成的。
它是消灭异步回调的终极武器;是同步语法,也就是用同步的写法写异步的代码。
二、使用规则
- async 表示这是一个async函数, await只能用在async函数里面,不能单独使用
- async 返回的是一个Promise对象,await就是等待这个promise的返回结果后,再继续执行
- await 等待的是一个Promise对象,后面必须跟一个Promise对象,但是不必写then(),直接就可以得到返回值
- 异步async 调用和普通函数的使用方式一样
async function Aa(){
return "abcdef"
}
const result =Aa();
console.log(result)
可以看出,async函数返回的是一个Promise对象,如果在函数中 return 一个直接量,async 会把这个直接量通过 Promise.resolve() 封装成 Promise 对象。
async 函数返回的是一个 Promise 对象,所以在最外层不能用 await 获取其返回值的情况下,我们当然应该用原来的方式:then() 链来处理这个 Promise 对象。
async function Aa(){
return "abcdef"
}
Aa().then(e=>{
console.log(e)
})
输出结果是abcdef,如果async函数没有返回值,则返回undefined。
在没有 await 的情况下执行 async 函数,它会立即执行,返回一个 Promise 对象,并且,绝不会阻塞后面的语句。这和普通返回 Promise 对象的函数并无二致。
可以认为 await 是在等待一个 async 函数完成。await 等待的是一个表达式,这个表达式的计算结果是 Promise 对象或者其它值
三、优点
- async/await是对promise的优化
- 同步代码和异步代码可以一起编写
- 同步代码编写方式,更符合代码编写习惯
- 多个参数传递Promise的then函数只能传递一个参数,虽然可以通过包装成对象来传递多个参数,但是会导致传递冗余信息,频繁的解析又重新组合参数,比较麻烦;async/await没有这个限制,可以当做普通的局部变量来处理,用let或者const定义的块级变量想怎么用就怎么用,想定义几个就定义几个,完全没有限制,也没有冗余工作。
- 基于协程:Promise是根据函数式编程的范式,对异步过程进行了一层封装,async/await基于协程的机制,是真正的“保存上下文,控制权切换……控制权恢复,取回上下文”这种机制,是对异步过程更精确的一种描述。
- 方便级联调用:即调用依次发生的场景。
四、案例
使用promise
methods: {
getLocation(phoneNum) {
return axios.post('/one接口', {
phoneNum
})
},
getFaceList(province, city) {
return axios.post('/two接口', {
province,
city
})
},
getFaceResult () {
this.getLocation(this.phoneNum).then(res => {
if (res.status === 200 && res.data.success) {
let province = res.data.obj.province;
let city = res.data.obj.city;
this.getFaceList(province, city).then(res => {
if(res.status === 200 && res.data.success) {
this.faceList = res.data.obj
}
})
}
}).catch(err => {
console.log(err)
})
}
}
async/ await案例:
async getFaceResult () {
try {
let location = await this.getLocation(this.phoneNum);
if (location.data.success) {
let province = location.data.obj.province;
let city = location.data.obj.city;
let result = await this.getFaceList(province, city);
if (result.data.success) {
this.faceList = result.data.obj;
}
}
} catch(err) {
console.log(err);
}
}
五、async/await和promise的关系
- async/await 是消灭异步回调的终极武器
- 但和Promise并不排斥,两者相辅相成
- 执行 async 函数,返回的是 Promsie 对象
- await 相当于 Promise 的 then ,then指的是成功,不指失败
- try…catch 可捕获异常,代替了 Promise的 catch
1. async
async function fn(){
return 100
}
console.log(fn()) //返回一个成功态的promise对象,result 是 100
fn().then(
data=>{
console.log(data)
}
) // 100
2. await
- await 后面接 Promise
1.await p1相当于是p1.then,并且只是成功态的then
2.await 和 then 的区别就是:then还需要传回调进去,但 await 可以直接得到值
(async function(){
const p1 = Promise.resolve(300) //一个成功态的promise对象,且传了result为300
const res = await p1 // return 值
console.log(res) // 300
})
- await 后面接 数值
1.await后面跟的不是promise对象而是数值时,会自动包装成成功态的promise对象
2.并且传值给 resolve 为400
(async function(){
const res = await 400 //Promise.resolve(400)
console.log(res) //400
})()
- await 后面接 async函数
(async function(){
const res = await fn() //fn()会返回promise对象,原理一样
console.log(res) //400
})()
- await 后面接 promise为空
1.什么都打印不出来
2.因为 new Promise 里面没有任何状态改变,而await一直在等待状态改变
3.只有状态改变了,await才会允许执行后面的代码
(async function(){
const p = new Promise(()=>{})
const res = await p
console.log(res)
console.log("success")
})()
- await 后面接 promise为error
1.会出现报错
2.await相当于成功态的.then ,都没有成功,因此不会执行后面的代码
3.因为JS是单线程的
4.解决:使用 try…catch 偷偷解决掉 error,保证代码运行
——捕获到错误就不会影响后面的输出
(async function(){
const p = Promise.reject("error")
const res = await p
console.log(res)
console.log("success")
})() //什么都打印不出来
(async function(){
const p = Promise.reject("error")
try{
const res = await p
console.log(res)
}catch(error){
console.log(error)
}
console.log("success")
})() //打印出 error 和 success
六、执行顺序
- 代码中存在 await,则需要等待该行执行完才执行下面的代码
function timeout(){
return new Promise(resolve=>{
setTimeout(()=>{
console.log(1)
resolve()//成功态
})
})
}
//情况一
async function fn(){
timeout()
console.log(2)
}
fn() //打印出 2 一秒后 1
//情况2
async function fn(){
await timeout()
console.log(2)
}
fn() //1秒后打印出 1 2
//写法二
function timeout(){
return new Promise(resolve=>{
setTimeout(()=>{
resolve(1)//成功态,传递参数1
})
})
}
async function fn(){
const res = await timeout() //需要一个变量来接收await return的参数
console.log(res)
console.log(2)
}
fn() //1秒后打印出 1 2