定義
- 同步: 一個程式在執行某個請求的時候,若該請求需要一段時間才能返回資訊,那麼這個程式將會一直等待下去,直到收到返回資訊才繼續執行下去
- 非同步: 程式不需要一直等下去,而是繼續執行下面的操作,不管其他程式的狀態。當有訊息返回時系統會通知程式進行處理,這樣可以提高執行的效率
- 執行緒: 執行緒是程式中一個單一的順序控制流程。程式內一個相對獨立的、可排程的執行單元,是系統獨立排程和分派CPU的基本單位。指執行中的程式的排程單位
- 單執行緒: 單執行緒在程式執行時,所走的程式路徑按照連續順序排下來,前面的必須處理好,後面的才會執行。單執行緒就是程式裡只有一個執行緒
問題
console.log(100)
setTimeout(function () {
console.log(200)
}, 0)
console.log(300)
輸出:
// 100
// 300
// 200
複製程式碼
解析
JS為單執行緒, 但是任務執行分為同步任務和非同步任務
程式碼中console.log為同步任務, setTimeout為非同步任務(這些基礎東西就不過多解釋了)
為了方便理解,我們可以認為JS這條單執行緒中有兩條事件佇列, 一條為同步佇列(主事件大迴圈 Event Loop),一條為非同步佇列,同步任務在同步佇列中依次執行,非同步任務在非同步佇列中依次執行,並且這兩個佇列是同時執行的。但是,JavaScript引擎只會執行同步佇列中的任務,那麼非同步佇列中的任務什麼時候執行呢?
JavaScript引擎會不斷遍歷同步佇列,當同步佇列為空時,會將非同步佇列中執行完畢的非同步事件的回撥函式放入同步佇列執行。
回顧
現在讓我們回來看看上面的面試題就很容易理解了,同步佇列中console.log(100)和console.log(300)執行後,console.log(200)被推入同步佇列執行,所以結果依次為100-> 300->200
PS: setTimeout(fun, 0)中的0不是立即執行的意思, 而是同步佇列為空時立即將fun推入同步佇列
額外
var flag = 1
setTimeout(function(){
flag = 0
}, 0)
while(flag){
console.log('running')
}
複製程式碼
結果是什麼?
答案為死迴圈,因為while(flag)中的程式碼將一直在同步佇列中執行,而flag = 0沒有機會被推入同步佇列