理解node.js中的 Event Loop
????node中的 “event loop” 正是node能處理高并發的核心所在。也正是因為它,node雖然在本質上是個單線程,卻能讓大量的操作處于后臺運行。這篇文章將詳細說明 event loop 的運行機制。
事件驅動編程
????為了理解 event loop,首先得明白事件驅動編程的概念。事件驅動編程的概念在20世紀60年代就廣為人知。在今天,它被廣泛應用于 UI 編程中。既然JavaScript最主要的作用是操作DOM,那么使用基于事件的 API 就再自然不過了。
????簡單來說,基于事件驅動的編程就是程序的控制流程基于事件或者事件狀態的轉變。常見的實現方式是定義一個核心機制用來監聽事件,當所監聽的事件發生時,或者狀態發生改變時,回調注冊在該事件上的回調方法。其實這也正是event loop背后的基本原理。
????如果你熟悉前端js開發,你可能會想起 .onXxx() 方法,例如 element.onclick(),這些方法正是監聽DOM元素上用戶的操作。這種模式適用于單個元素可能會觸發許多不同的事件的情景下。Node中的 EventEmitter 正是使用這種模式,它存在于node的Server,Socket和 http等多個模塊中。當我們需要從一個對象中發送多種狀態變化時,這種模式就非常好用。
????另外一種通用的模式是成功狀態的回調與失敗狀態的回調。目前主要有兩種實現方式,一種是錯誤優先的回調的模式:即發生錯誤時,錯誤信息作為第一個參數傳遞給回調方法。另外一種方式是ES6中的Promises。
????Node中的fs模塊主要是使用錯誤回調優先的方式。從技術上來講,對于某些調用,它可以發送額外事件,例如 fs.readFile(),但是API設計成只有當用戶指定的操作成功與失敗時才會通知用戶。API之所以設計如此,只是出于架構上的考慮而非技術的限制。
????一個常見的錯誤理解是,認為事件的發送器是異步的,其實不然,下面這個例子就能很好的說明:
function MyEmitter() {EventEmitter.call(this); } util.inherits(MyEmitter, EventEmitter);MyEmitter.prototype.doStuff = function doStuff() {console.log('before')emitter.emit('fire')console.log('after')} };var me = new MyEmitter(); me.on('fire', function() {console.log('emit fired'); });me.doStuff(); // 輸出結果為: // before // emit fired // after????EventEmitter 因為經常用來發送異步操作的完成從而常被誤解為其本身也是異步的,其實其本身是同步的。emit函數可能是異步調用的,但是需要注意的是,所有的回調函數都將按照它們注冊時的順序同步執行。
Event Loop 機制概述
Node本身依賴于多個庫,libuv就是其中一個。libuv負責處理隊列與進程中異步事件。
Node還會盡可能的利用操作系統中的功能,因此,諸如寫入請求、保持連接等都交給操作系統去處理,例如請求的連接首先會由操作系統處理,只有它們變得可用時node才會介入處理。
你可能了解node中有一個線程池,因此而產生疑問:既然Node都將那些耗時的操作交由操作系統來處理,那么它為何還需要線程池呢? 這是因為操作系統內核并不是對所有的操作都支持異步,在這種情況下,node需要鎖定那些在執行內核不支持異步操作的線程,而使用其他線程來事件循環從而不阻塞整個進程。
下圖是整個機制的簡圖:
另外還有兩個重要的點在圖中難以展示的是:
未完待續。。。。。
總結
以上是生活随笔為你收集整理的理解node.js中的 Event Loop的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 聊聊tomcat jdbc pool的默
- 下一篇: iOS面试题02-UI篇