在 Java、PHP 或者.net 等服務器端語言中,會爲每個客戶端鏈接建立一個新的線程。而每一個線程須要耗費大約 2MB 內存。也就是說,理論上,一個 8GB 內存的服務器能夠同時鏈接的最大用戶數爲 4000 個左右。要讓 Web 應用程序支持更多的用戶,就須要增長服務器的數量,而 Web 應用程序的硬件成本固然就上升了。node.js 不爲每一個客戶鏈接建立一個新的線程,而僅僅使用一個線程。當有用戶鏈接了,就觸發一個內部事件,經過非阻塞 I/O、事件驅動機制,讓 Node.js 程序宏觀上也是並行的。使用 Node.js,一個 8GB 內存的服務器,能夠同時處理超過 4 萬用戶的鏈接。node
可是在實際過程當中,非阻塞也會產生必定的問題,例如,咱們須要從後臺請求數據,而後拿到這些數據之後,執行某些操做,可是因爲非阻塞,不能控制獲取數據的時間,後續的操做就會出現問題。數組
在上面例子中,咱們但願先執行第一個打印,而後執行文件讀取,最後執行第四個打印。可是因爲Node是非阻塞的,在執行到文件讀取的時候,因爲文件大小的緣由,須要必定的時間,在這個時間裏,有並行處理了第四個打印,等第四個打印執行了,前面的文件讀取才執行結束,因而就有了下面的輸出服務器
一樣,在下面的例子中,一樣因爲執行文件讀取的時間過長,在讀取文件的時候,併發執行了打印事件,因此打印的時候,並無數據。併發
但是在實際項目中,這種結果是不能接受的,爲了保證能打印出數據,咱們但願在文件結束後,再執行打印事件,下面兩種辦法就是實現這個要求。異步
Node.js 有多個內置的事件,咱們能夠經過引入 events 模塊,並經過實例化 EventEmitter 類來綁定和監聽事件。函數
在使用events 模塊的時候,須要先引入改模塊,並建立 EventEmitter對象。ui
var events=require('events'); var EventEmitter=new events.EventEmitter();
而後在須要等待上面執行完畢再執行的事件裏面,綁定事件和事件處理程序spa
eventEmitter.on('eventName', eventHandler);
最後,在處理費時程序的地方,觸發上面的綁定.net
eventEmitter.emit('eventName');
綁定和觸發的事件名稱須要保持一致。線程
按照上面的方式,咱們能夠對前面的例子進行調整:
Node.js 全部的異步 I/O 操做在完成時都會發送一個事件到事件隊列,全部這些產生事件的對象都是 events.EventEmitter 的實例,EventEmitter 的核心就是事件觸發與事件監聽器功能的封裝。EventEmitter 對象若是在實例化時發生錯誤,會觸發 error 事件。當添加新的監聽器時,newListener 事件會觸發,當監聽器被移除時,removeListener 事件被觸發。