5分钟带你详细了解async/await

875 阅读4分钟

写在前面

之前我写过一篇文章关于JS中如何解决异步代码挂起的问题Js中异步代码挂起怎么解决? - 掘金 (juejin.cn),文中我主要讲了用Promise来解决异步问题,我们知道了可以用then链来解决多层回调问题,但是用then链的话写起来不够优雅,有点不符合原生JS写法的意思,asyncawait就很好地解决了这个问题,首先用async声明一个异步函数,然后再用await等待异步结果,把以前then链的结果放到直接放在await,非常方便。

async/await是什么?

async/await语法是在2016年时提出的,简单来说async/awaitPromise的语法糖,async是异步的意思,await是等待的意思。async function 申明一个函数里面可能有异步代码需要执行,await则可以认为是等待一个异步方法执行完成。

async/await的用法

我们直接来看下面的例子:

let data = {}
function getData1() {
    return new Promise((resolve, reject) => {
    //异步代码
        setTimeout(() => {
            data = { name: 'song', age: 20 }
            resolve()
        }, 1000)
    })

}
function getData2() {
    return new Promise((resolve, reject) => {
    //异步代码
        setTimeout(() => {
            data = { name: 'uiiy', age: 20 }
            resolve()
        }, 2000)
    })

}

function showData() {
    console.log(`我正在展示获取到的数据:${JSON.stringify(data)}`);
}

async function handle() {
    await getData1()
    await getData2()
    showData()
}

handle()

在上面的代码中我们可以看到getData1getData2两个函数中都有异步代码,我们用async/await来解决的话在函数体内和使用then链解决一样,都需要return出一个Promise。不同的点就在于async新定义了一个异步函数,getData1getData2两个函数在异步函数里面调用,然后在两个函数前面都加上await

async/await的特点

  1. async函数调用会返回一个Promise对象。
sync function handle() {
    //return new Promise(()=>{})
    return 'hello'
}

const res = handle()

console.log(res);

上面代码执行结果为:

1.png

  1. await 必须写在 async 函数里面。

这个特点很好理解,asyncawait是配套使用的,await规定了要写在 async里面。

  1. await 会阻塞下一行代码的执行,封装了Promise.then()

这也很好理解,我们知道需要耗时的代码都是异步代码,await加在了有异步代码的函数前面,一定要等这个函数执行完毕了才会执行下面的代码,要不然就解决不了异步代码挂起的问题了。

  1. await也会返回出一个Promise对象。
//await

function await() { 
    return Promise.resolve().then(() => { 
        
    })
}

一道面试题

将下面代码async/await翻译成Promise

function getJson() {
    return new Promise((resolve, reject) => {
        setTimeout(function () {
            console.log(2);
            resolve(2)
        }, 2000)
    })
}

async function testAsync() {
    await getJson()
    console.log(3);
}
testAsync()

我们可以根据async/await的特点翻译成下面的代码:

//翻译成Promise.then执行
function testAsync() {
    return Promise.resolve().then(() => {
        return getJson()
    }).then(() => {
        console.log(3);
    })
}

变化

如果题目中getJson函数里面没有返回一个Promise对象上面代码的执行结果会改变吗?

function getJson() {
        setTimeout(function () {
            console.log(2);
            resolve(2)
        }, 2000)
}

这里显然是会的,这样这个函数里面的异步代码将会挂起,先是输出3,再输出2

注意:then也会返回一个Promise对象

async/await的优点——和Promise比较

  • 同步代码编写方式,能处理由多个Promise组成的 then 链,async/await从上到下,顺序执行,更符合我们的编写习惯。
  • 同步代码和异步代码可以一起编写,用Promise最好将同步代码和异步代码放在不同的then节点中,这样结构更加清晰,而用async/await整个书写习惯都是同步的,不需要纠结同步和异步的区别。
  • 语法简洁清晰,节省了很多不必要的匿名函数。
  • 减少不必要的中间变量,更清晰明确的错误堆栈。

async/await的局限

  • 降低了我们阅读理解代码的速度,此前看到 .then() 就知道是异步,现在需要识别 asyncawait 关键字。

可以看出, async/await 的优势大部分都是从开发调试效率提升层面来讲的,提到的局限也只有不痛不痒的,所以说 async/await整体还是优雅的。

最后

async/await 相比于Promise是更优越的异步处理方案,但我们相信这一定不是终极处理方案。随着前端工程化的深入,一定有更多、更复杂、更精细的异步问题出现,同时也会有迎合这些问题的解决方案出现。最后感谢各位的观看,我们下篇文章见~