Event loop
event loop是計算機系統的一種運行機制,JavaScript就採用這種機制,來解決單線程運行帶來的一些問題。弄懂這個就能清楚的知道js究竟是怎樣去執行的。
咱們須要知道,js是單線程的,碰見異步操做會先進異步隊列,而不是當即執行,咱們須要知道如下兩個概念:segmentfault
宏隊列,macrotask,這些異步任務包括:
- setTimeout
- setInterval
- setImmediate (Node)
- requestAnimationFrame (瀏覽器)
- I/O
- UI rendering (瀏覽器)
微隊列,microtask,這些異步任務包括:
- Promise
- Object.observe
- MutationObserver
- process.nextTick (Node)

代碼執行步驟
- 執行全局Script同步代碼,這些同步代碼有一些是同步語句,有一些是異步語句(好比setTimeout等)
- 全局Script代碼執行完畢後,調用棧Stack會清空
- 從微隊列microtask queue中取出位於隊首的回調任務,放入調用棧Stack中執行,執行完後microtask queue長度減1
- 繼續取出位於隊首的任務,放入調用棧Stack中執行,以此類推,直到直到把microtask queue中的全部任務都執行完畢。注意,若是在執行microtask的過程當中,又產生了microtask,那麼會加入到隊列的末尾,也會在這個週期被調用執行
- microtask queue中的全部任務都執行完畢,此時microtask queue爲空隊列,調用棧Stack也爲空
- 取出宏隊列macrotask queue中位於隊首的任務,放入Stack中執行
- 執行完畢後,調用棧Stack爲空
- 重複第3-7個步驟
簡單點歸納就是同步代碼順序執行,碰到微任務進微隊列,碰到宏任務進宏隊列。同步代碼執行完先將微隊列中的全部任務執行完,微隊列執行過程當中碰到的微任務放到隊列尾部此次一併執行。微隊列執行完畢後執行宏隊列頭部的任務,執行完成以後再進微隊列,執行完全部的微任務,依次循環,直到全部任務執行完畢promise
console.log(1)
setTimeout(() => {
console.log(2)
Promise.resolve().then(() => {
console.log(3)
})
}, 0)
new Promise((resolve, reject) => {
console.log(4)
resolve(5)
}).then((res) => {
console.log(res)
})
setTimeout(() => {
console.log(6)
}, 0)
console.log(7)
// 輸出結果1 4 7 5 2 3 6
以上代碼的輸出結果你猜對了嗎?咱們來逐行分析瀏覽器
- 第一行,console.log直接輸出1
- 而後碰到第一個setTimeout,setTimeout屬於宏任務,進入宏隊列,繼續往下執行
- 碰到一個promise(注意:promise只有resolve/reject纔算異步),因此這裏4直接輸出,resolve進入微隊列
- 碰到第二個setTimeout,進宏隊列
- 7直接輸出
- 而後看微隊列,以前進隊列的依次出, 隊列裏面只有一個promise輸出5,而後隊列爲空
- 而後執行宏隊列第一個,輸出2,promise進微隊列
- 執行微隊列,輸出3,微隊列爲空
- 執行宏隊列第一個,輸出6,到這裏全部隊列爲空執行完畢
Promise.resolve().then(() => {
console.log('mm')
Promise.resolve().then(() => {
console.log('xx')
}).then(() => {
console.log('yy')
})
}).then(() => {
console.log('nn')
})
// 輸出結果mm xx nn yy
這段代碼的輸出結果你猜對了嗎?咱們再來分析:異步
- 首先看代碼中只有一個大promise,先執行,mm直接輸出,promise進微隊列,內部執行完畢
- 而後外層.then進微隊列
- 執行微隊列,輸出xx,碰到內部.then加入隊列尾部
- 輸出nn
- 輸出yy
參考:
https://segmentfault.com/a/11...