async/await详解

1,648 阅读5分钟

一、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)

image.png

可以看出,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