从一道题从新理解async/await

首先先列出题目,你们能够先思考下执行结果🤔。git

async function async1() {
    console.log('async1 start');
    await async2();
    await async3()
    console.log('async1 end');
}
async function async2() {
    console.log('async2');
}
async function async3() {
    console.log('async3');
}
console.log('script start');
setTimeout(function() {
    console.log('setTimeout');
}, 0)
async1();
new Promise(function(resolve) {
    console.log('promise1');
    resolve();
}).then(function() {
    console.log('promise2');
});
console.log('script end');

我相信在async/await函数那里,不少人(也许只有我)会出现理解误差,即:async函数执行相似同步函数,遇到await关键字,先执行await表达式,等到有返回结果再执行后面的操做。当仅仅只有一个async函数时,可能看不出问题,好比下面的题目。github

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

不出意外,你们的执行结果都是:// async start, async2,async endpromise

然而,若是是这样理解,我理解的执行结果应该是这样:网络

script start,async1 start,async2,async3,async1 end,promise1,script end,promise2,setTimeout异步

然而这个结果是不对的,正确的结果是:async

`script start,async1 start,async2,promise1,script end,
async3,promise2,async1 end,setTimeout`函数

出现这种误差的缘由是什么呢?所以咱们须要好好了解下async函数的机制。oop

定义
async函数定义了一个返回AsyncFunction的异步函数,它会隐式的返回一个Promise做为其返回结果。它的代码书语法和结构更像是同步函数。
描述

async函数体内能够包含多个await表达式(await关键字只能配合async使用),await指令会暂停异步函数的执行,等待Promise的返回结果,并返回结果。code

async function foo() {
    await 1
    console.log('async')
}

上面的函数实际上等价于:队列

function foo() {
    return Promise.resolve(1).then(() => console.log('async'))
}

<p style="color:red;font-weight: bold">
在await表达式以后的代码能够被认为是存在在链式调用的then回调方法中
</p>

基于上面的结论。所以,当执行await async2时,会将其后面的函数放入Promise.then的回调中(任务队列中),因此会继续执行下方的new Promise,其then方法的回调也会进入任务队列中。当执行栈中的同步任务执行完毕,从任务队列中取出第一个任务(async3函数),此时又遇到await关键字,所以,将console.log('async')语句加入任务队列中。此时会打印async3,而后执行new Promise的then回调打印promise2。以此内推,而后执行console.log('async')打印async。最后执行macroTask,打印setTimeout

注意:本文假设你对事件循环有必定基础,若是对事件循环(Event Loop)不熟悉,能够参考文后的事件循环参考。另外,若是页面中有多个网络请求,请不要使用async依次调用,因为async的机制,它将是串行的方式,建议使用Promise.all等其余方式。

总结

await会一直等待以后的表达式执行完以后才会继续执行后面的代码的误区走出来的一个重要总结就是:在await表达式以后的代码能够被认为是存在在链式调用的then回调方法中。

本文是我在作题目的参考MDN和其余文章的一些总结,若有理解误差的地方,但愿你们斧正。比心:)

参考

相关文章
相关标签/搜索