這裡主要記錄在日常中對知識的學習,通過結合筆記與自身理解的方式嘗試寫下總結
文章對細節可能不會一一介紹解釋,內容僅作參考
複製程式碼
一、背景
- JavaScript是一門單執行緒語言
- 單執行緒所帶來的任務執行方式
二、同步任務與非同步任務
單執行緒就意味著,所有的任務都需要排隊,當前一個任務結束時,才會執行後一個任務。如果前一個任務耗時很長,後一個任務就不得不一直等待。 如果是因為計算量大,CPU忙不過來倒也正常,但是很多時候CPU是閒著的,因為IO裝置(輸入輸出裝置)很慢(比如Ajax操作從網路讀取資料),不得不等著結果出來,再往下執行。
這時主執行緒完全可以不管IO裝置,掛起處於等待中的任務,先執行排在後面的任務。等到IO裝置返回了結果,再回過頭,把掛起的任務繼續執行下去。於是,所有任務可以分成兩種:
- 同步任務
- 非同步任務
在這裡用一張圖來說明:
- 同步和非同步任務分別進入不同的執行"場所",同步的進入主執行緒,非同步的進入Event Table
- 當非同步任務完成時,Event Table會將對應的回撥移入Event Queue中
- JS引擎會持續不斷檢查主執行緒執行棧是否為空,當主執行緒內的任務全部執行完畢後,會去Event Queue讀取排頭第一個,進入到主執行緒執行
- 上述過程不斷重複,形成事件迴圈(Event Loop)
三、巨集任務與微任務
除了廣義的同步任務和非同步任務,會對任務有更精細的定義:
- 巨集任務:整體程式碼、setTimeout、setInterval
- 微任務:Promise
不同型別的任務會進入對應的Event Queue,比如setTimeout和setInterval會進入相同的Event Queue
第一次進入整體程式碼(巨集任務)後,開始第一遍迴圈,在主執行緒任務全部執行完畢後,會先去讀取所有的微任務進行執行,然後再到巨集任務,而巨集任務裡面或許又包含著巨集任務與微任務。以此不斷迴圈執行
用一張圖說明:
舉個栗子
setTimeout(function() {
console.log('setTimeout')
})
new Promise(function(resolve) {
console.log('promise')
resolve()
}).then(function() {
console.log('then')
})
console.log('console')
複製程式碼
- 這段程式碼會作為巨集任務,進入主執行緒
- 先遇到setTimeout,將其放入Event Table,完成後會將其回撥函式註冊並放入到巨集任務Event Queue
- 接下來遇到了Promise,new Promise立即執行,然後遇到console.log('promise'),立即執行。then函式放入微任務Event Queue。
- 遇到console.log('console'),立即執行
- 整體程式碼作為第一個巨集任務執行結束,接著檢視是否有微任務?我們發現了then在微任務Event Queue裡面,執行
- 微任務全部執行完畢,第一輪事件迴圈結束,開始第二輪迴圈。從巨集任務Event Queue發現有setTimeout對應的回撥函式(多個巨集任務的時候取隊頭),立即執行
- 檢查無可執行任務,結束