一道神奇的async quiz

YuXitong發表於2018-05-25

原文連結:https://github.com/AlvinYuXT/blog/issues/4

Jake Archibald最近在twitter上出了一道簡單的quiz題目,問大家x的輸出是什麼。程式碼如下:

let x = 0;

async function test() {
    x+= await 2;
    console.log(x);
}

test();
x += 1;
console.log(x)
複製程式碼

看到這裡我想,這不就是在考microTask和marcoTask嗎?那麼答案應該不難,執行順序是這樣的:

  1. 先執行test函式,test函式中直接就進入到x+=await 2了,那麼放到microTask中
  2. 執行x+=1
  3. 執行console.log(x),輸出結果是1
  4. 當前作用域沒有macro要執行了,所以執行microTask,執行x+=await 2;console.log(x)輸出結果應該是3

錯!!!

實際上不是這樣的,而這裡我對async/await中什麼內容放到microtask也存在錯誤的理解。正確的執行順序是這樣的

  1. 執行test函式此時x+=await 2等價於x = x + await Promise.resolve(2),表示式右邊在求值的時候遇到了await,所以這個時候x已經求值了,也就是說上面的函式等價於x = 0 + await Promise.resolve(2)。這裡還有一點需要注意的是Promise只有then和catch裡面的是真正非同步執行的,想new Promise(resolve=>{console.log(123)})這種事直接同步執行的,而這裡的Promise.resolve(2)也是同步執行的。
  2. 這個時候繼續執行x+=1;console.log(x)輸出的結果是1
  3. macroTask執行結束之後去執行microTask,這個時候就會回來執行x = 0 + 2;console.log(x),所以這個時候輸出的是2

注意:await後面的語句並不是放到micro去執行的,而是直接同步執行的。也就是說await並不直接將後面要執行的程式碼放到microTask中,await只是等待microTask執行完才把await後面的表示式求值結果返回給左值。

相關文章