從一道題從新理解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和其餘文章的一些總結,若有理解誤差的地方,但願你們斧正。比心:)

參考

相關文章
相關標籤/搜索