谈谈 async 和 await 的用法

293 阅读2分钟

async/await

async 会返回 promise,await 等待一个 promise resolve 的值,如果等待非 promise,会返回该值本身,相当于 await Promise.resolve(xxx)

光看起来没什么难度,我们来看一下大厂常考的事件循环的面试题

async function async1() {
    console.log('async1 start');
    await async2();
    console.log('async1 end');
}

async function async2() {
    console.log('async2 start');
    return new Promise((resolve, reject) => {
        resolve();
        console.log('async2 promise');
    })
}

async1();
new Promise(function (resolve) {
    console.log('promise1');
    resolve();
}).then(function () {
    console.log('promise2');
}).then(function () {
    console.log('promise3');
}).then(()=>{
    console.log('promise4')
})

结果如下

image.png 对于此类问题,我的解决方法是将其改写为 promise 的形式,那么我们开始吧

对于第一个 async 函数

async function async1() {
    console.log('async1 start');
    await async2();
    console.log('async1 end');
}

我们知道 await 在等待 async2 的结果 resolve 之后,再去将第四行代码当作 then 的回调,那么可得出以下结论

function async1(){
    console.log('async1 start')
    return new Promise((resolve,reject)=>{
        async2().then(()=>{
            resolve()
        }).then(()=>{
           console.log('async1 end');
        })
    })
}

对于第二个 async 函数

async function async2() {
    console.log('async2 start');
    return new Promise((resolve, reject) => {
        resolve();
        console.log('async2 promise');
    })
}

我们看到,函数主动返回了一个 promise,那么最终返回的 promise 由你手动返回的 promise 来决定,所以可得出以下结论

function async2(){
    console.log('async2 start')
    return new Promise((resolve,reject)=>{
        new Promise((resolve2,reject2)=>{
            resolve2()
            console.log('async2 promise')
        }).then(()=>{
            resolve()
        })
    })
}

等待手动返回的 promise resolve 后,返回的 promise 才会 resolve

也就是说,外界 await 等待的是 async 自动包装的 promise 的 resolve,而不是我们手动返回的 promise,所以我的用词是 ‘手动返回的 promise’ 和 ‘返回的 promise’,要区分清楚

然后我们试验一下改写后的形式,是否和原来一样

function async1(){
    console.log('async1 start');
    return new Promise((resolve,reject)=>{
        async2().then(()=>{
            resolve()
        }).then(()=>{
            console.log('async1 end');
        })
    })
}
function async2(){
    console.log('async2 start');
    return new Promise((resolve,reject)=>{
        new Promise((resolve2,reject2)=>{
            resolve2()
            console.log('async2 promise');
        }).then(()=>{
            resolve()
        })
    })
}
async1();
new Promise(function (resolve) {
    console.log('promise1');
    resolve();
}).then(function () {
    console.log('promise2');
}).then(function () {
    console.log('promise3');
}).then(()=>{
    console.log('promise4')
})

image.png 我们掌握了改写技巧后,就能轻易地判断事件循环啦

还有几种其他的情况,比如

async function async1(){
    console.log('async1')
}
// 等价于
function async1(){
    console.log('async1')
    return Promise.resolve(undefined)
}
async function async1(){
    await console.log('async1')
}
// 等价于
function async1(){
    console.log('async1')
    return Promise.resolve(undefined)
}

核心就是每个函数 resolve 的时机,当然要对 promise 有一定的理解才行,建议多手写 promise 来加深理解