初探nodejs事件循環機制event loop

nodejs的特色html

nodejs 具備事件驅動和非阻塞I/O的特色。node

事件驅動是指nodejs把每個任務當成事件來處理。socket

非阻塞I/O是nodejs遇到I/O任務時,會從線程池調度單獨的線程處理I/O操做,不會阻塞主線程。函數

事件循環原理oop

Node.js 在主線程裏維護了一個事件隊列,當接到請求後,就將該請求做爲一個事件放入這個隊列中,而後繼續接收其餘請求。spa

當主線程空閒時(沒有請求接入時),就開始循環事件隊列,檢查隊列中是否有要處理的事件,這時要分兩種狀況:線程

  若是是非 I/O 任務,就親自處理,並經過回調函數返回到上層調用;code

  若是是 I/O 任務,就從 線程池 中拿出一個線程來處理這個事件,並指定回調函數,而後繼續循環隊列中的其餘事件。htm

當線程中的 I/O 任務完成之後,就執行指定的回調函數,並把這個完成的事件放到事件隊列的尾部,等待事件循環,當主線程再次循環到該事件時,就直接處理並返回給上層調用。blog

流程圖

每次循環的六個階段

  timers階段:這個階段執行定時器隊列中的回調,如 setTimeout() 和 setInterval()

  I/O callbacks: 這個階段執行幾乎全部的回調。可是不包括close事件,定時器和setImmediate()的回調。

  idle, prepare: 這個階段僅在內部使用,能夠沒必要理會。

  poll: 等待新的I/O事件,node在一些特殊狀況下會阻塞在這裏。

  check: setImmediate()的回調會在這個階段執行。

  close callbacks: 例如socket.on('close', ...)這種close事件的回調。

 

下面咱們來按照代碼第一次進入libuv引擎後的順序來詳細解說這些階段:

  當個v8引擎將js代碼解析後傳入libuv引擎後,循環首先進入poll階段。

  poll階段的執行邏輯以下:

    先查看poll queue中是否有事件,有事件就按先進先出的順序依次執行回調。

    當queue爲空時,會檢查是否有setImmediate()的callback,若是有就進入check階段執行這些callback。

    當queue爲空時,同時也會檢查是否有到期的timer,若是有,就把這些到期的timer的callback按照調用順序放到timer queue中,以後循環會進入timer階段執行queue中的 callback。

    這二者的順序是不固定的,收到代碼運行的環境的影響。

    若是二者的queue都是空的,那麼loop會在poll階段停留,直到有一個i/o事件返回,循環會進入i/o callback階段並當即執行這個事件的callback。

    值得注意的是,poll階段在執行poll queue中的回調時實際上不會無限的執行下去。

    有兩種狀況poll階段會終止執行poll queue中的下一個回調:1.全部回調執行完畢。2.執行數超過了node的限制。

 

參考連接:

http://www.javashuo.com/article/p-fliavhij-eb.html

http://www.javashuo.com/article/p-spnkobdq-dt.html

相關文章
相關標籤/搜索