中文字幕av专区_日韩电影在线播放_精品国产精品久久一区免费式_av在线免费观看网站

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

node.js的事件機制

發布時間:2020-10-10 08:45:23 來源:腳本之家 閱讀:172 作者:楊帥前端攻城獅 欄目:web開發

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

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

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

我們來看下單進程和多進程的區別:

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

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

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

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

具體來分呢, 單進程對比多進程有什么優點呢:

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

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

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

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

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

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

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

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

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

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

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

舉個小栗子

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

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

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

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

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

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

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

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

事件驅動程序

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

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

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

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

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

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

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

舉個栗子

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

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

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

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

在事件驅動模型中,會生成一個主循環來監聽事件,當檢測到事件時觸發回調函數。

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

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

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

上代碼:

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

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

結果是符合預期的。

但是有一點需要注意哦, 當你想移除事件的時候, 直接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 還提供了只觸發單次事件的方法~

eventObj.once(‘起床', getUp)

還有移除全部事件呀~

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

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

eventObj.listeners(even)  返回指定事件的監聽器數組

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

按照參數的順序執行事件,  返回值是true或者false。有此監聽事件就返回true。

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

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

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

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

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

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

在 Node 應用程序中,執行異步操作的函數將回調函數作為最后一個參數, 回調函數接收錯誤對象作為第一個參數。

接下來讓我們來重新看下前面的實例,創建一個 input.txt ,文件內容如下:

123456123123

創建 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("程序執行完畢");

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

如果沒發生錯誤,readFile 跳過 err 對象的輸出,文件內容就通過回調函數輸出。

執行以上代碼,執行結果如下:

123456123123

接下來我們刪除 input.txt 文件,執行結果如下所示:

程序執行完畢Error: ENOENT, open 'input.txt'

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

以上就是本文的全部內容,希望本文的內容對大家的學習或者工作能帶來一定的幫助,同時也希望多多支持億速云!

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

抚松县| 龙井市| 常熟市| 乌兰察布市| 台前县| 利津县| 兰溪市| 习水县| 新野县| 聂荣县| 宝应县| 溧水县| 武山县| 汕尾市| 尉犁县| 临安市| 应城市| 兰溪市| 山东| 阿坝| 松原市| 井冈山市| 富源县| 务川| 临漳县| 环江| 镇坪县| 清原| 巩留县| 榆树市| 黄浦区| 广灵县| 桐梓县| 桦甸市| 南投市| 鄯善县| 都昌县| 平乡县| 马鞍山市| 舟山市| 祥云县|