nodejs中的eventLoop

小兔子發表於2018-04-08

javascript與nodejs的事件環

nodejs的event是基於libuv,而瀏覽器的event loop則在html5的規範中明確定義。

瀏覽器中的事件環

nodejs中的eventLoop
js中的事件環

  1. 所有同步任務都在主執行緒上執行,形成一個執行棧
  2. 主執行緒之外,還存在一個任務佇列。只要非同步任務有了執行結果,就在任務佇列之中放置一個事件。
  3. 一旦執行棧中的所有同步任務執行完畢,系統就會讀取任務佇列,將佇列中的事件放到執行棧中依次執行
  4. 主執行緒從任務佇列中讀取事件,這個過程是迴圈不斷的
console.log(1)
setTimeout(function(){
    console.log(2)
    setTimeout(function(){
        console.log(3)
    })
})
setTimeout(function(){
    console.log(4)
})
console.log(5)
複製程式碼
  1. 列印結果:15243
  2. 存放在任務佇列中的事件有:onclick,onload,ajax,setTimeout,setInterval等非同步方法
  3. 執行棧中的方法總是在任務佇列前執行,任務佇列中的執行順序是先進先出

nodejs中的事件環

Node.js也是單執行緒,但是它的event loop執行機制不同於瀏覽器環境。

nodejs中的eventLoop
nodejs中的事件環

  1. 我們寫的js程式碼會交給v8引擎進行處理
  2. 程式碼中可能會呼叫nodeApi,node會交給libuv庫處理
  3. libuv通過阻塞i/o和多執行緒實現了非同步io
  4. 通過事件驅動的方式,將結果放到事件佇列中,最終交給我們的應用。

nodejs中事件迴圈的幾個階段 在libuv內部有這樣一個事件環機制。在node啟動時會初始化事件環

   ┌───────────────────────┐
┌─ │     timers(計時器)     │
|  |   執行setTimeout以及   |
|  |   setInterval的回撥。  |
│  └──────────┬────────────┘
│  ┌──────────┴────────────┐
│  │     I/O callbacks     |
│  |   處理網路、流、tcp的錯誤 |
|  | callback              |
│  └──────────┬────────────┘
│  ┌──────────┴────────────┐
│  │     idle, prepare     │
|  |     node內部使用       |
│  └──────────┬────────────┘      
│  ┌──────────┴────────────┐      ┌───────────────┐ 
│  │       poll(輪詢)       │      │   incoming:   │
|  | 執行poll中的i/o佇列     | ─────┤  connections, │
|  | 檢查定時器是否到時       |      │   data, etc.  |  
│  └──────────┬────────────┘      └───────────────┘    
│  ┌──────────┴────────────┐      
│  │      check(檢查)       │
|  | 存放setImmediate回撥    |
│  └──────────┬────────────┘
│  ┌──────────┴────────────┐
└──┤    close callbacks    |
   │ 關閉的回撥例如          |
   | sockect.on('close')   |
   └───────────────────────┘
複製程式碼

階段總覽

  1. timers:執行setTimeout()和setInterval安排的回撥
  2. I/O callbacks: 執行幾乎所有異常的close回撥,由timer和setImmediate執行的回撥。
  3. idle,prepare: 只用於內部
  4. poll : 獲取新的I/O事件,node在該階段會適當的阻塞
  5. check : setImmediate的回撥被呼叫
  6. close callbacks: e.g socket.on(‘close’,…);
  7. 在每次執行事件迴圈之間,node.j檢查是否有正在等待的非同步i/o呼叫、timers等。如果沒有,就清除並結束(退出程式),例如:執行一個程式,僅有一句話(var a= ‘hello’;),處理完目的碼後,不會進入evetloop,而是直接結束程式。

階段詳解

  1. timers,定時器階段: 執行定時任務(setTimeOut(), setInterval())
  1. setTimeout 和 setImmediate 二者非常相似,但是二者區別取決於他們什麼時候被呼叫.
  • setImmediate 設計在poll階段完成時執行,即check階段;
  • setTimeout 設計在poll階段為空閒時,且設定時間到達後執行;但其在timer階段執行 其二者的呼叫順序取決於當前event loop的上下文,如果他們在非同步i/o callback之外呼叫(在i/o內呼叫因為下一階段為check階段),其執行先後順序是不確定的,需要看loop的執行前的耗時情況
  1. poll階段
    nodejs中的eventLoop

poll 輪詢階段:

  1. 處理到期的定時器任務,然後(因為最開始階段佇列為空,一旦佇列為空,就會檢查是否有到期的定時器任務)
  2. 處理佇列任務,直到佇列空,或達到上限
  3. 如果佇列為空:如果setImmediate,終止輪詢階段,進入檢查階段執行。如果沒setImmediate,檢視有沒有定時器任務到期,有的話就到timers階段,執行回撥函式.
  1. check階段

poll階段變為空閒、等待狀態時,一旦呼叫setImmediate(),eventloop會進入check 階段,而不是在poll階段等待。

  1. close callbacks階段

例如:socket或控制程式碼關閉,close事件會觸發這個階段。或者通過process.nextTick()觸發

參考檔案

nodejs官方文件之event

相關文章