async/await是什么

async/await 是ES2017(ES8)提出的基于Promise的解决异步的最终方案。

async

async是一个加在函数前的修饰符,被async定义的函数会成为异步函数,异步函数的返回值会自动封装到一个Promise对象里,最后默认返回一个Promise对象

async function fn() {
    return 20
}
let result = fn()
//返回的是一个Promsie对象
console.log(result)

await

await 也是一个修饰符
await 修饰的如果是Promise对象:可以获取Promise中返回的内容(resolve或reject的参数),且取到值后语句才会往下执行
await只能放在async定义的函数内,或es模块的顶级作用域中。可以理解为等待。所以它不会阻塞async外面的代码,而async里在await后的代码必定依赖于await返回的结果,如果不依赖那么写在await前面即可,所以这个阻塞是不影响运行效率的

function sum(a, b) {
    return new Promise(resolve => {
        setTimeout(() => {
            resolve(a + b)
        })
    })
}
async function fn3() {
    let result3 = await sum(1, 2)
    console.log(result3)
    console.log('async里面')
}
fn3()
console.log('async外面');
//输出结果为:async外面 3 async里面

如果不是Promise对象:把这个非promise的东西当做await表达式的结果。

可以利用await来替代链式调用

async function fn() {
    let result = await sum(1, 2)
    result = await sum(result, 4)
    result = await sum(result, 5)
    console.log(result)
}
fn()
//返回值为12

await一般与async配合使用,如果async里没有await,那么它就与普通函数一样依次执行

async function fn() {
    console.log(1);
    console.log(2);
    console.log(3);
}
fn()
console.log(4);
//输出结果为 1 2 3 4

等价于

function fn() {
    return new Promise(resolve => {
        console.log(1);
        console.log(2);
        console.log(3);
        resolve()
    })
}
fn()
console.log(4);
//输出结果为 1 2 3 4 

当我们使用await调用函数后,当前函数后边的所有代码会在当前函数执行完毕后,被放入微任务队列

async function fn() {
    console.log(111)
    await console.log(222)
    //await后边的代码,都会被放入到微任务队列中执行
    console.log(333)
}
fn()
console.log(444);
输出结果为: 111 222 444 333

相当于

function fn() {
    return new Promise(resolve => {
        console.log(11)
        console.log(22)
        resolve()
    }).then(r => {
        console.log(33)
    })
}
fn()
console.log(44)

try-catch

通过await调用异步代码时,需要通过try-catch来处理异常

try {
    let result = await sum(1, 2)
    console.log(result)
}catch(e) {
    console.log('出错了~~~');
}

es模块

在html文件里我们无法直接使用await

 <script>
        await console.log(2333)
 </script>
 //报错:Uncaught SyntaxError: await is only valid in async functions and the top level bodies of modules

将script标签变成模块就可以使用了

 <script type="module">
        await console.log(2333)
    </script>
//控制台输出2333

还有我们在js文件里只能在async声明的函数里使用await
在mjs文件里则可以直接使用await

立即执行函数

我们在非es模块使用await时需要创建函数再调用函数

async function fn() {
    await console.log('haha')
}
fn()

有点繁琐
可以用匿名的方式写成立即执行函数

(async () => {
    await console.log('haha')
})()

这两个是等价的