我已經迷失在事件環(event-loop)中了【Nodejs篇】

小美娜娜發表於2018-08-13

我第一次看到他事件環(event-loop)的時候,我是一臉懵,這是什麼鬼,是什麼迴圈嗎,為什麼event還要loop,不是都是一次性的嗎?

瀏覽器中和nodejs環境中的事件環是有一些區別的,這裡我只研究了nodejs環境,小黑框情況下的事件環。

這裡的事件環並不是指單獨一件事件的迴圈,而是我們寫的很多很多的事件按照一定地規則排著隊去執行,然後佇列清空後繼續排隊,就是事件環。

事件環很複雜,這裡我只有能力解釋事件環中的幾個點:

node.js中對於事件環的解釋

nodejs中將eventloop分成了:

  • timers: 定時器setTimeout執行,將callback加入佇列中。
  • pending callbacks: 一些I/O的callback,推遲到下一次迴圈中執行。
  • idle, prepare: 內部的一些事件。
  • poll: 定時器的callback執行,setImmediate執行,微任務執行。
  • check: setImmediate的callback執行。
  • close callbacks: 一些callbacks的關閉,如socket。

這邊我們專注於timers、poll和check這三個階段。其他的我們用的不多。

timers、poll、check階段

  • timers

這個階段,只執行setTimeout和setInterval,但是他們的callback不會執行,而是推到巨集任務的佇列之中。

  • poll

這個階段,會先執行符合條件的微任務,比如Promise的非同步完成,如果是setImmediate,則只會執行,不執行他的callback,然後執行定時器的callback,比如timeout。這裡會適當得暫停一會,看看會不會有新任務進入佇列。如果有setImmediate的callback則進入check 階段,否則回到timer繼續新一輪迴圈。

  • check

當poll階段的佇列完成,則會輪到check,這時會執行setImmediate的callback。如果沒有需要關閉callbacks,那麼就回到timer繼續新一輪的迴圈。

巨集任務 vs 微任務

  • 巨集任務

從我的角度理解,就是一個正常的task,本來在一個執行緒中可以毫無波折地一個接著一個執行到最後,奈何每個巨集任務執行之後都有可能產生一些微任務,因此很不幸,這些巨集任務就要排在這些微任務之後了。

巨集任務代表:script(整體程式碼),setTimeout,setImmediate。

/**
output:
我先走一步
你太慢了,我插個隊
老司機,等等我
*/
setTimeout(()=>{
    console.log("我先走一步") 
})
setTimeout(()=>{
    console.log("老司機,等等我")
},10)
setImmediate(()=>{
    console.log("你太慢了,我插個隊")
})
複製程式碼

劃重點

setTimeout和setImmediate,觸發的階段不同,因此callback執行時間也不同。但是如果setTimeout的時間過長,那麼系統會先執行setImmediate,然後等下一輪詢中,如果setTimeout到時間了,那麼就執行setTimeout的callbacks。

  • 微任務

就是巨集任務執行時,產生的新的小任務,比如非同步,此類任務稱之為微任務,一般在當前巨集任務執行完之後“插隊”執行。

微任務代表:process.nextTick, Promise(原生)。

劃重點

雖然process.nextTick和Promise都是微任務,但是他們的執行的先後順序是不一樣的。無論誰的程式碼先執行,等到了poll階段,兩者都是可執行的狀態時,都是nextTick先於Promise執行。

/**
output:
本宮始終是你望成莫及的
總有一日,我會上位
*/
Promise.resolve().then(()=>{
    console.log("總有一日,我會上位") 
})
process.nextTick(()=>{
    console.log("本宮始終是你望成莫及的") 
})
複製程式碼

後記:

我只寫了我對於eventloop的理解,但是還有很多雲裡霧裡的地方,寫出來的只是我理解的。

相關文章