await會阻塞其所在表示式中後續表示式的執行

郭某某發表於2019-02-22

在進入正文之前,我們首先來看一段程式碼,這段程式碼會輸出什麼呢?

let x = 0;

async function test() {
    x += await 2;
    console.log(x);	// 輸出什麼?
}

test();
x = 1;
複製程式碼

輸出3?還是2?正確答案是:2

如果你知道為什麼會輸出2,那就不用繼續閱讀本文了;但如果你清除這裡面的原因,那麼你可以跟隨我一起分析一下:

  1. 首先我們先記住一句話,那就是非同步函式(async方式宣告的函式)不代表其函式內部的所有程式碼都是非同步方式執行的,這句話什麼意思呢?通俗講就是:在第一個await表示式出現之前,非同步函式內部的程式碼都是按照同步方式執行的,記住這句話以後我們再繼續往下看

  2. 那麼在test函式內部,哪些程式碼是按同步方式執行的呢?首先我們可以將x += await 2這行程式碼稍微變換一下形式,變換為:x = x + await 2,表示式右邊的x是取值操作,並且按同步方式執行的,所以在執行到await時,右邊的x已經取值完成,並且被取到的值0替換,然後才輪到test函式外的x = 1這行程式碼執行,x += await 2相當於x = 0 + await 2,所以最終輸出:2

現在,我們稍微對上面的程式碼做一下修改:

let x = 0;

async function test() {
    x = (await 2) + x;// 把await放在x前面
    console.log(x);	 // 這裡又輸出什麼?
}

test();
x = 1;
複製程式碼

如果你已經明白了前面我所說的,那麼我想你應該可以給出正確的答案,那就是輸出:3。原因是:await 2這次被放在了x表示式的前面,所以x的取值操作是非同步執行的,也就是說x = 1會先被執行,然後才是test函式中x的取值操作,由於test函式中的x形成了閉包,所以x = (await 2) + x相當於x = (await 2) + 1,所以最終輸出:3

結論

上面程式碼的關鍵是:test函式中x的取值操作與x = 1這行程式碼執行順序先後的問題,所以我們可以得出一個結論:await會阻塞其所在表示式中後續表示式的執行

原文連結:https://www.guoyunfeng.com/2018/05/28/await/

相關文章