欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

node.js的事件機制

 更新時間:2017年02月08日 14:11:21   作者:楊帥前端攻城獅  
本文主要介紹了node.js的事件機制,具有很好的參考價值,下面跟著小編一起來看下吧

首先, 補充下對node 的理解:

nodeJs 是一個單進程單線程應用程序, 但是通過事件和回調(diào)支持并發(fā), 所以性能非常高~

那么什么是單進程單線程呢~(寫給語文跟我一樣不好的小伙伴)

我們來看下單進程和多進程的區(qū)別:

1.  多進程的優(yōu)勢在于任務的獨立性,比如某個任務單獨作為一個進程的話,崩潰只影響自己的服務,其他任務不受影響.如果是多個任務在同一個進程內(nèi)部利用多個線程進行處理,某個線程發(fā)生了未處理的異常的話,會導致整個進程完蛋,所有的任務跟著遭殃

2.  從資源分配上來說,多進程方案比多線程方案更加靈活和自由

3. 不過任務間的通信方面多進程要比多線程復雜些,編一個好的多進程通信方案要比多線程間的通信方案困難多了(小伙伴們注意區(qū)分進程和線程喲~)

以web server為例的話,比如我的服務器上架設了三個網(wǎng)站,如果是用一個進程管理的話, 網(wǎng)站A遭受攻擊死掉了,意味著另外兩個網(wǎng)站會出現(xiàn)同樣的現(xiàn)象. 如果是分開獨立的進程的話,三個網(wǎng)站互不影響

具體來分呢, 單進程對比多進程有什么優(yōu)點呢:

1)  初期實現(xiàn)起來比較簡單快速, 而且不用考慮進程間通信的工作量

2) 單一性使得部署和運營比較簡單(這還用說  / 白眼ing)

3) 內(nèi)存占用少, 不過呢, 現(xiàn)在內(nèi)存很廉價, 但是一分錢也是錢呀!

4) 進程內(nèi)部通信效率比IPC/scoket(多進程數(shù)據(jù)通訊的終端)等要高效,  我一嗓子你就聽見了, 就不用費力氣裝個電話了

當然, 肯定優(yōu)缺點!不然花那么多錢開多進程的人也太蠢了 ~

單進程對比多進程的缺點~

1) 中后期隨著業(yè)務邏輯的復雜化和需求的增加,這個單進程會變得臃腫, 難以維護。 一個任務分解成多個進程會使單個進程的邏輯簡單,而不容易出錯

2) 同進程內(nèi)模塊間是強依賴關(guān)系,需要在一起編譯相互的影響也比較大。 這相對于多進程間通信來說, 耦合度較大(不符合高內(nèi)聚低耦合的偉大思想), 不利于多團隊并行開發(fā)。 多進程更便于多語言的協(xié)作開發(fā)。

3)任何模塊的崩潰都將導致整個進程的失效,多進程模式更加穩(wěn)定健壯,業(yè)務處理程序隔離運行, 一個go home不會影響其他(你敢崩我也崩);

4) 性能問題: 如果不支持進程間數(shù)據(jù)通訊的話,單進程的容量是受限的, 這個性能瓶頸對于支持群組類服務的尤其需要考慮。多進程部署極其靈活,可以擴充機器數(shù)量來提高系統(tǒng)處理性能,還可以從硬件上避免單點故障。(一個人承受不來)

5) 單進程中多線程難調(diào)試( 一槍開出去, 一群人倒了, 我還得檢查一下誰中槍了才能給你debug)

舉個小栗子

你有一個對象, 對象特別挑食, 但是對象只喜歡一種菜, 你每天做給她吃。

這就是個單進程單線程的模型,  如果你做的不好吃了, 對象不吃了。

但是我有一個對象, 她喜歡吃10種菜, 我每天端過去10份, 哪天其中某一份醋放多了, 對象說真難吃, 今天不吃了。這就是單進程多線程的模型。一個菜不好吃導致對象不吃了(全部線程崩掉)

..  如果我有兩個對象..  每個對象喜歡吃一種菜

ok,  一個對象覺得好吃, 吃的臉圓圓的三下巴, 一個覺得不好吃常年不吃, 骨瘦如柴。

這就是多進程單線程互不影響的模型.. 多進程多線程我就不舉栗了 ~

說到這里, 小伙伴有沒有對單進程單線程有一些理解呢。nodeJs 就是單進程單線程的應用程序, 進程間互不影響, 綁定多個事件可以同時觸發(fā)~  不用等你完了我再有動作, 所以nodeJs性能很高。

nodeJs 單線程類似進入一個while(true ) 的事件循環(huán), 知道沒有事件觀察者的時候退出(每綁定一個事件, 就生成一個事件觀察者), 當有事件發(fā)生的時候, 就會調(diào)用該事件的回調(diào)函數(shù)。

事件驅(qū)動程序

nodeJs 使用事件驅(qū)動模型(稍后說), 當web server 接收到請求時, 就把它關(guān)閉然后進行處理, 然后去服務下一個web 請求。可以理解成我觸發(fā)事件, 就先關(guān)閉這個事件驅(qū)動, 然后處理, 我覺得是在防止二次觸發(fā)~ 造成不正確的負載和意料之外的結(jié)果,這個模型非常高效可擴展性非常強,因為webserver一直接受請求而不等待任何讀寫操作。(這也被稱之為非阻塞式IO或者事件驅(qū)動IO)

可能有的小伙伴會問了, 什么是 事件驅(qū)動模型呢~ 

其實在了解事件驅(qū)動之前, 我們可以先看一下事件驅(qū)動的三大要素:

1) 事件源:  誰來接受外部事件

2) 偵聽器:  能夠接收事件源通知的對象

3) 事件處理程序:  用于處理事件

好, 包含以上三點的就是一個完整的事件驅(qū)動程序。

舉個栗子

如果有一天你走在路上一不小心被天上掉下來的花瓶砸到了,并且暈死了過去。那么整個過程其實就是一個事件處理流程,而且我們可以非常方便的分析出剛才所提到的事件驅(qū)動模型中的三大要素。

1.被砸暈的這個人其實就是事件源,因為他是能夠接受到外部的事件的源體。

2.偵聽器就是這個人的大腦神經(jīng),因為它會感知到疼痛。

3.事件處理就是這個人暈死了過去。

在事件驅(qū)動模型中,會生成一個主循環(huán)來監(jiān)聽事件,當檢測到事件時觸發(fā)回調(diào)函數(shù)。

整個事件驅(qū)動的流程就是這么實現(xiàn)的,非常簡潔。有點類似于觀察者模式,事件相當于一個主題(Subject),而所有注冊到這個事件上的處理函數(shù)相當于觀察者(Observer)。

說了那么多, 事件綁定怎么寫呢。

在node 里, 有個事件模塊 events,  我們可以通過實例化的events 對象 來綁定事件。

上代碼:

var event = require('events'); // 引入事件模塊
var eventObj = new event(); // 實例化一個事件對象
eventObj.on('起床', function() { // 綁定事件和事件回調(diào)
console.log('洗臉刷牙');

});
eventObj.emit('起床'); // 觸發(fā)事件的方法

結(jié)果是符合預期的。

但是有一點需要注意哦, 當你想移除事件的時候, 直接eventObj.removeListener(‘起床')

然后各種報錯~

其實正確的移除事件的方法是這樣的~

上代碼:

var event = require('events'); // 引入事件模塊
var eventObj = new event(); // 實例化一個事件對象
function getUp() {
console.log('洗臉刷牙');
}
eventObj.on('起床', getUp);
eventObj.emit('起床');
eventObj.removeListener('起床', getUp);
eventObj.emit('起床');

成功移除事件~

node 還提供了只觸發(fā)單次事件的方法~

eventObj.once(‘起床', getUp)

還有移除全部事件呀~

eventObj.removeAllListeners(getUp), 像我這樣指定了getUp的事件, 則移除所有觸發(fā)該事件的監(jiān)聽器。

eventObj.setMaxListeners(n)  參數(shù)是一個數(shù)字, 因為node默認了綁定事件最多10個, 10個以上的時候會警告。 如果不想被警告就設置最大監(jiān)聽器個數(shù)咯~

eventObj.listeners(even)  返回指定事件的監(jiān)聽器數(shù)組

eventObj.emit(getUp, [arg1], [arg2], [...])

按照參數(shù)的順序執(zhí)行事件,  返回值是true或者false。有此監(jiān)聽事件就返回true。

不知道小伙伴們有沒有疑惑,  我明明已經(jīng)把events 模塊加載過來了, 為什么還要實例化才能用呢~ 

大多數(shù)時候我們不會直接使用 EventEmitter,而是在對象中繼承它。包括 fs、net、 http 在內(nèi)的,只要是支持事件響應的核心模塊都是 EventEmitter 的子類。

為什么要這樣做呢?原因有兩點:

首先,具有某個實體功能的對象實現(xiàn)事件符合語義(可以自己命名了啊喂(#`O′) ), 事件的監(jiān)聽和發(fā)射都應該是一個對象的方法。

其次 JavaScript 的對象機制是基于原型的, 支持部分多重繼承,繼承 EventEmitter不會打亂對象原有的繼承關(guān)系。

Node 應用程序是如何工作的?

在 Node 應用程序中,執(zhí)行異步操作的函數(shù)將回調(diào)函數(shù)作為最后一個參數(shù), 回調(diào)函數(shù)接收錯誤對象作為第一個參數(shù)。

接下來讓我們來重新看下前面的實例,創(chuàng)建一個 input.txt ,文件內(nèi)容如下:

123456123123

創(chuàng)建 main.js 文件,代碼如下:

var fs = require("fs");
fs.readFile('input.txt', function (err, data) {
 if (err){
 console.log(err.stack);
 return;
 }
 console.log(data.toString());});
console.log("程序執(zhí)行完畢");

以上程序中 fs.readFile() 是異步函數(shù)用于讀取文件。 如果在讀取文件過程中發(fā)生錯誤,錯誤 err 對象就會輸出錯誤信息。

如果沒發(fā)生錯誤,readFile 跳過 err 對象的輸出,文件內(nèi)容就通過回調(diào)函數(shù)輸出。

執(zhí)行以上代碼,執(zhí)行結(jié)果如下:

123456123123

接下來我們刪除 input.txt 文件,執(zhí)行結(jié)果如下所示:

程序執(zhí)行完畢Error: ENOENT, open 'input.txt'

因為文件 input.txt 不存在,所以輸出了錯誤信息。

以上就是本文的全部內(nèi)容,希望本文的內(nèi)容對大家的學習或者工作能帶來一定的幫助,同時也希望多多支持腳本之家!

相關(guān)文章

最新評論