对async await的初步认识

133 阅读4分钟

「这是我参与2022首次更文挑战的第10天,活动详情查看:2022首次更文挑战」。

一、含义

async 函数是 ES2017 标准引入的更加好的一种异步编程解决方案。它使得异步编程更加方便,并且提供了在不阻塞主线程的情况下使用同步代码异步访问资源的能力。本质上,async 函数是 Generator 函数的语法糖。async 函数就是将 Generator 函数的星号(*)替换成 async,将 yield 替换成 await,仅此而已。

二、用法

1. async 函数搭配 await 的基本用法如下:

  • async 表示函数里有异步操作,其返回值是一个 Promise 对象,这也就意味着可以使用 then 方法添加回调函数。
  • await 表示紧跟在后面的表达式需要等待结果,该表达式是一个 Promise 对象。

1.1.定义 getMinNumber() 及 compareNumber()

    // 通过 async/await 调用 getMinNumber 函数,将其结果作为返回值
    async compareNumber() {
      const minNumber = await this.getMinNumber(2, 3)
      return minNumber
    },

    // 定义一个返回值为 Promise 的函数 getMinNumber
    getMinNumber(num1, num2) {
      return new Promise(function(resolve, reject) {
        setTimeout(function() {
          if (num1 < num2) {
            resolve(num1)
          } else {
            reject('失败')
          }
        }, 2000)
      })
    }

1.2.打印 compareNumber() 并查看结果

console.log(this.compareNumber())

结果如图:

由上图可知 async 函数的返回值是一个 Promise 对象

1.3.对于 async 函数返回的 Promise 对象使用 then 方法添加回调函数获取数据

this.compareNumber().then(data => {
   console.log('较小的值是:' + data)
})

结果如图:

由上图可知,2 和 3 比较,较小的值是 2。

2.需要注意的是:

当函数执行的时候,对于 async 函数返回的 Promise 对象,必须等到内部所有 await 命令后面的 Promise 对象执行完,才会发生状态改变,除非遇到 return 语句或者抛出错误。也就是说,只有 async 函数内部的异步操作执行完,才会执行 then 方法指定的回调函数

2.1.定义多个 await,具体代码如下:

// 通过 async/await 调用 getMinNumber 函数,将其结果作为返回值
    async compareNumber() {
      const minNumber1 = await this.getMinNumber(2, 3)
      const minNumber2 = await this.getMinNumber(1, minNumber1)
      return minNumber2
    },

    // 定义一个返回值为 Promise 的函数 getMinNumber
    getMinNumber(num1, num2) {
      return new Promise(function(resolve, reject) {
        setTimeout(function() {
          if (num1 < num2) {
            resolve(num1)
          } else {
            reject('失败')
          }
        }, 2000)
      })
    }

2.2.调用 compareNumber()

this.compareNumber().then(data => {
   console.log('较小的值是:' + data)
})

结果如图:

上面代码中,先执行函数 compareNumber 中的第一个 await 拿到较小值 2 以后,再执行第二个 await,将 2 与 1 再进行比较,最终拿到较小值 1,然后才会执行 then 方法里面的 console.log 将较小值 1 打印出来。

3.错误处理

Promise 基本用法详解这篇文章中,我们讲到在使用 Promise 时,异步函数有两个可能的返回值(成功时的返回及失败时的返回)。对于成功时的返回,我们可以使用 then,对于失败时的返回,我们可以使用 catch。同样的在使用 async/await 时,我们也会有成功和失败的情况,该文章的前半部分我们理想化的针对成功时的情况做了分析,下面我们将分析当失败时,如何对这些错误进行处理。

值得注意的是,当 async 函数里面有多个 await 时,如果某个 await 后面的 Promise 对象的状态变为 reject,那么整个 async 函数都会被中断。

第一个 await,返回的是"失败",第二个 await 不执行:

	// 通过 async/await 调用 getMinNumber 函数,将其结果作为返回值
    async compareNumber() {
      await this.getMinNumber(3, 2)
      await this.getMinNumber(4, 5)
    },

    // 定义一个返回值为 Promise 的函数 getMinNumber
    getMinNumber(num1, num2) {
      return new Promise(function(resolve, reject) {
        setTimeout(function() {
          if (num1 < num2) {
            resolve(num1)
          } else {
            reject('失败')
          }
        }, 2000)
      })
    }

打印及输出:

this.compareNumber().then(data => {
   console.log(data)
})

结果如图:

显然,这种做法不是很妥,因为有时我们希望即使前一个异步操作失败,也不要中断后面的异步操作。这时可以将第一个 await 放在 try...catch 结构里面,这样不管这个异步操作是否成功,第二个 await 都会执行。

    // 通过 async/await 调用 getMinNumber 函数,将其结果作为返回值
    async compareNumber() {
      try {
        await this.getMinNumber(3, 2)
      } catch (e) {
        console.log(e)// 失败
      }
      return await this.getMinNumber(4, 5)
    },

结果如图:

另一种方法是await后面的 Promise 对象再跟一个catch方法,处理前面可能出现的错误。

    // 通过 async/await 调用 getMinNumber 函数,将其结果作为返回值
    async compareNumber() {
      await this.getMinNumber(3, 2).catch(e => console.log(e))
      return await this.getMinNumber(4, 5)
    },

结果如图:

所以,综上所述,如果有多个 await,可以统一放在 try...catch 中。

三、总结

对于 async/await,其实还有许多地方我还没理解,可以多参考一些大佬的心得,推荐看看这个:es6.ruanyifeng.com/#docs/async