node.js事件輪詢(1)

事件輪詢(引用)html

事件輪詢是node的核心內容。一個系統(或者說一個程序)中必須至少包含一個大的循環結構(我稱之爲「泵」),它是維持系統持續運行的前提。nodejs中同樣包含這樣的結構,咱們叫它「事件輪詢」,它存在於主線程中,負責不停地調用開發者編寫的代碼。咱們能夠查看nodejs官方網站上對nodejs的說明:node

Node is similar in design to and influenced by systems like Ruby's Event Machine or Python's Twisted. Node takes the event model a bit further, it presents the event loop as a language construct instead of as a library. In other systems there is always a blocking call to start the event-loop. Typically one defines behavior through callbacks at the beginning of a script and at the end starts a server through a blocking call like EventMachine::run(). In Node there is no such start-the-event-loop call. Node simply enters the event loop after executing the input script. Node exits the event loop when there are no more callbacks to perform. This behavior is like browser JavaScript -— the event loop is hidden from the user.編程

node在設計上相似於Ruby的Event Machine或Python的Twisted等系統,並受其影響。 node進一步採用事件模型,它將事件循環呈現爲語言構造而不是庫。 在其餘系統中,老是有一個阻塞調用來啓動事件循環。 一般,經過在腳本開頭的回調定義行爲,最後經過阻塞調用(如EventMachine :: run())啓動服務器。 在Node中沒有這樣的啓動 - 事件循環調用。 node在執行輸入腳本後簡單地進入事件循環。 當沒有更多的回調要執行時,Node退出事件循環這種行爲就像瀏覽器JavaScript - 事件循環對用戶是隱藏的。瀏覽器

從中能夠看出,其餘語言當存在阻塞的時候纔會調用event loop,而node會在輸入腳本的時候就會進入事件循環。
ruby

咱們能夠看到,在nodejs中這個「循環」結構對開發者來說是不可見的。(借用別人的圖)服務器

如上圖所示,每一個異步函數執行結束後,都會在事件隊列中追加一個事件(同時保存一些必要參數)(這裏面有以下內容1.node怎麼判斷這個異步程序執行完了 2.執行完後,是怎麼放入到事件隊列中的)。事件輪詢下一次循環即可取出事件,而後會調用(這個事件對應的)異步方法對應的回調函數(參數,Q:怎麼區分這個回調函數是屬於這個事件(或者說是這個異步方法的?))。這樣一來,nodejs便能保證開發者編寫的每行代碼(每一個回調)均在主線程中執行。
1.異步程序的過程當中,若是出錯,則該異步結果會直接進入到事件隊列中,傳入的參數將會是回調函數的第一個參數。框架

2.若是開發者在回調函數中調用了阻塞方法,那麼整個事件輪詢就會阻塞,事件隊列中的事件得不到及時處理,node就會卡死,隨後就會崩潰。正由於這樣,nodejs中的一些庫方法均是異步的,也提倡用戶調用異步方法。若是在回調函數中產生錯誤,則從  調用對應的異步函數   ->  取事件 形成阻塞,node就會崩潰。異步

 

其實看到這裏的時候,若是有對Windows編程(尤爲對Windows界面編程)比較瞭解的讀者可能已經聯想到了Windows消息循環。函數

沒錯,nodejs中的事件輪詢原理跟Windows消息循環的原理相似。開發者編寫的代碼均運行在主線程中,若是你編寫了阻塞代碼,在Windows桌面程序中,因爲消息得不到及時處理,界面就會卡死。oop

我們再來看一下下面的nodejs代碼:

var fs = require('fs');
fs.readFile('hello.txt', function (err, data) {  //異步讀取文件
  console.log("read file end");
});
while(1){
    console.log("call readFile over");
}

如上,雖然咱們使用異步方法讀取文件,可是文件讀取完畢後「read file end」永遠不會輸出,也就是說readFile方法的回調函數不會執行。緣由很簡單,由於後面的主進程的while循環一直沒退出,致使下一次事件輪詢不能開始,因此回調函數不能執行(包括其餘全部回調)。事實再次證實,開發者編寫的全部代碼均只能運行在同一線程之中(姑且稱之爲主線程吧)。

關於異步方法

所謂異步方法,就是調用該方法不會阻塞調用線程,哪怕方法內部要進行耗時操做。你能夠理解爲方法內部單獨開闢了一個新線程去處理任務(主進程一直進行工做,而開的新線程處理異步的工做),而調用異步方法僅僅是開啓這個新線程。下面的代碼模擬一個異步方法的內部結構(僅僅是模擬,不表明實際):

在.NET中,每一個異步方法的回調函數均在另一個線程中執行(非調用線程),而在nodejs中,每一個異步方法的回調函數仍然還在調用線程上(能夠理解爲主線程)執行。至於爲何,你們能夠看一下前面講事件輪詢的部分,nodejs中每一個回調函數均由主線程中的事件輪詢來調用。這樣才能保證在nodejs中,開發者編寫的任何代碼均在同一個線程中運行(所謂的單線程)。http://www.cnblogs.com/xiaozhi_5638/p/4268223.html

消息循環就應該是"泵",消息隊列就應該是"數據容器",Windows消息就應該是"數據",而窗口過程就應該是"處理者",那麼整個結構應該

 

既然框架可以保證最終應用程序的持續正常工做,按照本章前面的結論,那說明框架內部必然有一種結構可以重複性處理問題,這種結構就是"泵",泵的"持續性"和"動力性"特性徹底知足框架的需求。若是須要將這種抽象關係圖形化顯示出來,見下圖10-18:

既然咱們最終的應用程序是在框架的基礎之上擴展出來的,這說明應用程序的主要運行邏輯、主要的流程控制均是由框架決定的,框架控制應用程序的啓動、決定主要的流程轉向,負責調用框架使用者編寫的"擴展代碼",總之,框架可以保證最終應用程序的持續正常工做。

這些 擴展代碼 就是常常說到的 Hook函數(或者一些屬性),而後模板的其餘的內容就是寫死的。只有Hook是固定的。

相關文章
相關標籤/搜索