原文連結: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嗎?那麼答案應該不難,執行順序是這樣的:
- 先執行test函式,test函式中直接就進入到
x+=await 2
了,那麼放到microTask中 - 執行
x+=1
- 執行
console.log(x)
,輸出結果是1 - 當前作用域沒有macro要執行了,所以執行microTask,執行
x+=await 2;console.log(x)
輸出結果應該是3
錯!!!
實際上不是這樣的,而這裡我對async/await中什麼內容放到microtask也存在錯誤的理解。正確的執行順序是這樣的
- 執行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)
也是同步執行的。 - 這個時候繼續執行
x+=1;console.log(x)
輸出的結果是1 - macroTask執行結束之後去執行microTask,這個時候就會回來執行
x = 0 + 2;console.log(x)
,所以這個時候輸出的是2
注意:await後面的語句並不是放到micro去執行的,而是直接同步執行的。也就是說await並不直接將後面要執行的程式碼放到microTask中,await只是等待microTask執行完才把await後面的表示式求值結果返回給左值。