1. 程式人生 > >Nodejs學習筆記(二)--- 事件模組

Nodejs學習筆記(二)--- 事件模組

目錄

簡介及資料

eventsnode.js 最重要的模組,events模組只提供了一個物件events.EventEmitter,EventEmitter 的核心是事件發射與事件監聽器。

Node.js中大部分的模組,都繼承自Event模組。

與DOM樹上事件不同,不存在事件冒泡、逐層捕獲等行為。

EventEmitter 支援若干個事件監聽器。當事件發射時,註冊到這個事件的事件監聽器被依次呼叫,事件引數作為回撥函式引數傳遞。   

  如何訪問:

require('events');

emitter.on(event, listener)

 

/*
    呼叫events模組,獲取events.EventEmitter物件
*/
var EventEmitter = require('events').EventEmitter;   
var ee = new EventEmitter();

/*
    EventEmitter.on(event, listener) 為事件註冊一個監聽
    引數1:event  字串,事件名
    引數2:回撥函式
*/
ee.on('some_events', function(foo, bar) {
    console.log("第1個監聽事件,引數foo=" + foo + ",bar="+bar );
});

console.log(
'第一輪'); ee.emit('some_events', 'Wilson', 'Zhong'); console.log('第二輪'); ee.emit('some_events', 'Wilson', 'Z');
EventEmitter.on(event, listener) 示例原始碼

emitter.emit(event, [arg1], [arg2], [...])

 

var EventEmitter = require('events').EventEmitter;   
var ee = new EventEmitter();

ee.on(
'some_events', function(foo, bar) { console.log("第1個監聽事件,引數foo=" + foo + ",bar="+bar ); }); /* EventEmitter.emit(event, [arg1], [arg2], [...]) 觸發指定事件 引數1:event 字串,事件名 引數2:可選引數,按順序傳入回撥函式的引數 返回值:該事件是否有監聽 */ var isSuccess = ee.emit('some_events', 'Wilson', 'Zhong'); ee.on('some_events', function(foo, bar) { console.log("第2個監聽事件,引數foo=" + foo + ",bar="+bar ); }); ee.emit('some_events', 'zhong', 'wei'); var isSuccess2 = ee.emit('other_events', 'Wilson', 'Zhong'); console.log(isSuccess); console.log(isSuccess2);
emitter.emit(event, [arg1], [arg2], [...]) 示例原始碼

示例進行了三次觸發事件操作,其中some_events註冊了監聽,呼叫時emit函式會返回一個true,而other_events並沒有註冊監聽,emit函式會返回一個false,表示該事件沒有監聽;當然也可以不用管這個返回值!

emitter.once(event, listener)

 

var EventEmitter = require('events').EventEmitter;   
var ee = new EventEmitter();

/*
    EventEmitter.once(event, listener)  為事件註冊一次性監聽,觸發一次後移除監聽
    引數1:event  字串,事件名
    引數2:回撥函式
*/
ee.once('some_events', function(foo, bar) {
    console.log("第1個監聽事件,引數foo=" + foo + ",bar="+bar );
});


console.log('第一輪');
ee.emit('some_events', 'Wilson', 'Zhong');

console.log('第二輪');
var isSuccess =  ee.emit('some_events', 'Wilson', 'Zhong');
console.log(isSuccess);
emitter.once(event, listener) 示例原始碼

從上面示例程式碼執行結果可以看出,用emitter.once給some_events註冊一個監聽後,分兩輪呼叫emitter.emit觸發,第二輪會返回false;這表示用emitter.once註冊監聽和用前面講的emitter.on註冊監聽略有不同,

emitter.once註冊監聽是一次性監聽,當觸發一次後,會移除該監聽!當然,從名字上就看就比較明顯了^_^!

emitter.removeListener(event, listener)

 先來看一個失敗的場景~~~

var EventEmitter = require('events').EventEmitter;   
var ee = new EventEmitter();

ee.on('some_events', function(foo, bar) {
    console.log("第1個監聽事件,引數foo=" + foo + ",bar="+bar );
});

/*
    看到API中removeListener移除方法時,以為應該是這樣
    但是結果^_^!!!!!
*/
ee.removeListener('some_events', function(){
    console.log('成功移除事件some_events監聽!');        
});

console.log('第一輪');
ee.emit('some_events', 'Wilson', 'Zhong');
emitter.removeListener(event, listener) 示例失敗場景原始碼

當我用emitter.on給some_events註冊了一個監聽後,我用emiiter.removeListener移除some_events的監聽,隨後再呼叫emitter.emit去觸發,最後發現不是按我想像的在進行!為什麼呢?

我理所當然的認為emiiter.removeListener第二個引數是個回撥函式,API還是要認真看清楚啊!!!

下面再看個成功的場景~~~

var EventEmitter = require('events').EventEmitter;   
var ee = new EventEmitter();

var listener = function(foo,bar)
{
    console.log("第1個監聽事件,引數foo=" + foo + ",bar="+bar );
}

var listener2= function(foo,bar)
{
    console.log("第2個監聽事件,引數foo=" + foo + ",bar="+bar );
}

var listener3= function(foo,bar)
{
    console.log("第3個監聽事件,引數foo=" + foo + ",bar="+bar );
}

ee.on('some_events', listener);

ee.on('some_events', listener2);

ee.on('some_events', listener3);
/*
    EventEmitter.removeListener(event, listener)  移除指定事件的監聽器
    注意:該監聽器必須是註冊過的
    PS:上一個例子之後以會失敗,很大原因就是忽略了監聽器,理所當然的認為傳個事件名就OK了,所以就悲劇了!
*/
ee.removeListener('some_events', listener);

ee.removeListener('some_events', listener3);

ee.emit('some_events', 'Wilson', 'Zhong');
emitter.removeListener(event, listener) 示例成功場景原始碼

我用示例中寫法,給some_events添加了三個監聽,又移除了第一個和第三個監聽,最後再用emitter.emit觸發some_events,輸出結果不難發現,用emitter.removeListener移除的第一個和第三個監聽都沒有再起作用,

想當然是害人地,原來emitter.removeListener的第二個引數是要移除的監聽,而非移除成功後的回撥函式……^_^!

emitter.removeAllListeners([event])

emitter.removeListener用過了,但一個事件可以有多個監聽,需要全部移除時,一個個移除明顯不是愉快的做法,不符合偷懶的天性!

讓我們來體驗一下emitter.removeAllListeners帶來的便捷!

var EventEmitter = require('events').EventEmitter;   
var ee = new EventEmitter();

var listener = function(foo,bar)
{
    console.log("第1個監聽事件,引數foo=" + foo + ",bar="+bar );
}

var listener2= function(foo,bar)
{
    console.log("第2個監聽事件,引數foo=" + foo + ",bar="+bar );
}

ee.on('some_events', listener);

ee.on('some_events', listener2);

ee.on('other_events',function(foo,bar)
{
    console.log("其它監聽事件,引數foo=" + foo + ",bar="+bar );
});

/*
    EventEmitter.removeAllListeners([event])   移除(批定事件)所有監聽器
    引數1:可選引數,event  字串,事件名
*/
ee.removeAllListeners('some_events');

ee.emit('some_events', 'Wilson', 'Zhong');

ee.emit('other_events', 'Wilson', 'Zhong');
emitter.removeAllListeners 傳入事件名引數示例原始碼

看看上面的執行結果,你會發現給some_events註冊了兩個監聽;給other_events註冊了一個監聽;我呼叫emitter.removeAllListeners傳了some_events事件名;

最後使用emitter.on函式觸發some_events和other_events兩個事件,最後發現some_events註冊的兩個監聽都不存在,而other_events註冊的監聽還存在;

這表示當 emitter.removeAllListeners傳用事件名作為引數時,為移除傳入事件名的所有監聽,而不會影響其它事件監聽!

 emitter.removeAllListeners可以不傳用事件名引數;直接執行

var EventEmitter = require('events').EventEmitter;   
var ee = new EventEmitter();

var listener = function(foo,bar)
{
    console.log("第1個監聽事件,引數foo=" + foo + ",bar="+bar );
}

var listener2= function(foo,bar)
{
    console.log("第2個監聽事件,引數foo=" + foo + ",bar="+bar );
}

ee.on('some_events', listener);

ee.on('some_events', listener2);

ee.on('other_events',function(foo,bar)
{
    console.log("其它監聽事件,引數foo=" + foo + ",bar="+bar );
});

/*
    EventEmitter.removeAllListeners([event])   移除(批定事件)所有監聽器
    引數1:可選引數,event  字串,事件名
*/
ee.removeAllListeners();

ee.emit('some_events', 'Wilson', 'Zhong');

ee.emit('other_events', 'Wilson', 'Zhong');
emitter.removeAllListeners 不傳引數示例原始碼

示例程式碼和傳入引數時幾乎一樣,只是在呼叫emitter.removeAllListeners並沒有傳入指定事件名;

執行結果會發現some_events和other_events所有監聽都不存在了,它會移除所有監聽!(比較暴力的方法一般要慎用~~)

emitter.listeners(event)

 

var EventEmitter = require('events').EventEmitter;   
var ee = new EventEmitter();

var listener = function(foo,bar)
{
    console.log("第1個監聽事件,引數foo=" + foo + ",bar="+bar );
}

var listener2= function(foo,bar)
{
    console.log("第2個監聽事件,引數foo=" + foo + ",bar="+bar );
}

ee.on('some_events', listener);

ee.on('some_events', listener2);

ee.on('other_events',function(foo,bar)
{
    console.log("其它監聽事件,引數foo=" + foo + ",bar="+bar );
});

/*
    EventEmitter.listeners(event)   //返回指定事件的監聽陣列
    引數1:event  字串,事件名    
*/
var listenerEventsArr = ee.listeners('some_events');

console.log(listenerEventsArr.length)

for (var i = listenerEventsArr.length - 1; i >= 0; i--) {
    console.log(listenerEventsArr[i]); 
};
emitter.listeners(event) 示例原始碼

給some_events註冊兩個監聽,呼叫emitter.listeners函式,傳入some_events事件名,接收函式返回值;

從結果可以看出,返回值接收到some_events所有註冊監聽的集合!

emitter.setMaxListeners(n)

 一個事件可以新增多個監聽是沒錯,但Nodejs預設最大值是多少呢?

var EventEmitter = require('events').EventEmitter;   
var ee = new EventEmitter();

/*
     給EventEmitter 新增11個監聽
*/
for (var i = 10; i >= 0; i--) {
    ee.on('some_events',function()
    {
        console.log('第'+ (i +1) +'個監聽');
    });
};
新增N個監聽示例原始碼

上面示例中我用個迴圈給some_events新增11個監聽,執行程式碼,發現warning資訊出現,並且提示的比較詳細了,需要用emitter.setMaxListeners()去提升限值

var EventEmitter = require('events').EventEmitter;   
var ee = new EventEmitter();

/*
    EventEmitter.setMaxListeners (n)   給EventEmitter設定最大監聽
    引數1: n 數字型別,最大監聽數
    
    超過10個監聽時,不設定EventEmitter的最大監聽數會提示:
    (node) warning: possible EventEmitter memory leak detected. 11 listeners added.
     Use emitter.setMaxListeners() to increase limit.
    設計者認為偵聽器太多,可能導致記憶體洩漏,所以存在這樣一個警告
*/
ee.setMaxListeners(15);

/*
     給EventEmitter 新增11個監聽
*/
for (var i = 10; i >= 0; i--) {
    ee.on('some_events',function()
    {
        console.log('第'+ (i +1) +'個監聽');
    });
};
emitter.setMaxListeners 示例原始碼

當我呼叫emitter.setMaxListeners傳入15時,執行程式碼,warning資訊不再出現;

emitter.setMaxListeners的作用是給EventEmitter設定最大監聽數,感覺一般是不需要設定這個值,10個還不夠用的情況應該是比較少了!

設計者認為偵聽器太多會導致記憶體洩漏,所有就給出了一個警告!

其它...

 用的比較少的就不詳細說了

EventEmitter.defaultMaxListeners

EventEmitter.defaultMaxListeners功能與setMaxListeners類似,
給所有EventEmitter設定最大監聽
setMaxListeners優先順序大於defaultMaxListeners

EventEmitter.listenerCount(emitter, event)

返回指定事件的監聽數

 特殊的事件Error

引用自Node.js開發指南:EventEmitter 定義了一個特殊的事件 error,它包含了“錯誤”的語義,我們在遇到 異常的時候通常會發射 error 事件。當 error 被髮射時,EventEmitter 規定如果沒有響 應的監聽器,Node.js 會把它當作異常,退出程式並列印呼叫棧。我們一般要為會發射 error 事件的物件設定監聽器,避免遇到錯誤後整個程式崩潰。

事件的繼承

相關推薦

Nodejs學習筆記--- 事件模組

目錄 簡介及資料 events是node.js 最重要的模組,events模組只提供了一個物件events.EventEmitter,EventEmitter 的核心是事件發射與事件監聽器。 Node.js中大部分的模組,都繼承自Event模組。 與DOM樹上事件不同,不存在事件冒

Nodejs學習筆記--- 操作MongoDB數據庫

效果 view asc erro eve mongdb splay play 所有 最近看了一些關於mongodb的文章,然後就想知道nodeJS是怎麽連接的所以我就嘗試去了解了一波(這個菜鳥驛站這個網站還不錯,雖然知識文檔不是最新的,但是還是蠻好的;   順便官網地址是

QT學習筆記——基礎模組

QT基礎模組: Qt Core,提供核心的非 GUI 功能,所有模組都需要這個模組。這個模組的類包括了動畫框架、定時器、各個容器類、時間日期類、事件、IO、JSON、外掛機制、智慧指標、圖形(矩形、路徑等)、執行緒、XML 等。所有這些類都可以通過 <QtCore> 標頭檔案引入。

nodejs學習筆記——javascript的同步非同步行為和多執行緒

寫過後臺的同學一定對執行緒、執行緒池或者是多執行緒這些概念不會陌生,但是前臺在HTML5之前很少會提及,因為在HTML5之前javascript都是單執行緒的。下面用一個簡單的例子來說明一下單執行緒: setInterval(function(){ var date

React 學習筆記 事件、約束與非約束性元件

事件物件 方法一 方法二 方法三 表單取值 鍵盤事件 react實現雙向資料繫結 約束性元件和非約束性元件 非約束性元件 defaultValue:<input type="text" defaultValue=‘111’/>

java丨事件驅動程式設計學習筆記

一、匿名監聽器 監聽器類是特意為建立一個GUI元件(例如,一個按鈕)而設計的監聽物件。監聽器類不被其他應用程式所共享,因此,正確的做法是將它作為一個內部類定義在框架中。 可以使用匿名內部類簡化內部類監聽器。匿名內部類時沒有名字的內部類。它進一步完成定義內部類和建立一個該類的例項。 內部類Enlarg

BOM學習筆記繫結事件處理函式、history、location

5、navigator物件包含有關瀏覽器的資訊              navigator物件集合            

機器學習筆記:python 模組pandas

1.讀csv檔案資料 import pandas as pd Info = pd.read_csv('titanic_train.csv'); #print(type(Info)) #Info的型別 <class 'pandas.core.frame

Nodejs學習筆記--- 模組

目錄 簡介及資料 通過Node.js的官方API可以看到Node.js本身提供了很多核心模組 http://nodejs.org/api/ ,這些核心模組被編譯成二進位制檔案,可以require('模組名')去獲取;核心模組具有最高的載入優先順序(有模組與核心模組同名時會體現) (本次主要說

extjs4學習筆記----- 監聽事件beforeload使用

EXTJS4 store 監聽事件beforeload使用(grid帶引數,查詢,分頁) 最近看store發現一個方法–beforload,官網定義 在一個新資料物件請求發出前觸發此事件. 如果beforeload的處理函式返回’false’, 資料請求

iOS開發學習筆記 -- 動態新增控制元件和事件處理

剛開始學iOS開發的時候,經常要跟interface builder打交道,乍一看拖控制元件是挺方便的,跟以前做C#開發類似,但是Xcode比較噁心的一點是,拖完控制元件之後,還得手動地在Connections Inspector中繫結控制元件和變數的關係,事件的繫結也在這

php laravel框架學習筆記 數據庫操作

true 數據 mar sql show top 一行 ati del 原博客鏈接:http://www.cnblogs.com/bitch1319453/p/6810492.html mysql基本配置 你可用通過配置環境變量,使用cmd進入mysql,當然還有一種東

java學習筆記圖形用戶接口

star strong per getwidth cep runnable graphics s2d gb2 這個學期主要放在ACM比賽上去了,比賽結束了。不知不覺就15周了,這周就要java考試了,復習一下java吧。java的學習的目的還是讓我們學以致用,讓我們可以

數據結構學習筆記 線性表的順序存儲和鏈式存儲

出錯 初始化 node != test span 輸入 des val 線性表:由同類型數據元素構成有序序列的線性結構  --》表中元素的個數稱為線性表的長度  --》沒有元素時,成為空表  --》表起始位置稱表頭,表結束位置稱表尾 順序存儲:    1 package

Memcache 學習筆記---- PHP 腳本操作 Memcache 服務器

ext status ram var_dump 介紹 修改 memcache local dbn    PHP 腳本操作 Memcache 服務器 一、PHP腳本操作Memcache方法     使用 PHP 腳本操作 Memcache,在 PHP 手冊中有詳細的介紹,我們

javascript學習筆記:定義函數、調用函數、參數、返回值、局部和全局變量

兩個 cnblogs bsp 結果 value ava ase com 調用 定義函數、調用函數、參數、返回值 關鍵字function定義函數,格式如下: function 函數名(){ 函數體 } 調用函數、參數、返回值的規則和c語言規則類似。 1 <!DOC

神箭手爬蟲學習筆記

暫存 自動 表達 eve doc 常用 學習 數據 .sh 一,可以使用神劍手已經做好的爬蟲市場直接跑,不需要自己定義爬取規則 二,爬蟲市場裏沒有的網站,需要自己去定義規則來爬數據。 三,爬取的數據可以先存放在神劍手,也可以放到七牛暫存。(提醒下,網站需要數據備份如果數量不

thinkphp5.0學習筆記API後臺處理與命名空間

mac code 輸入 -1 pub 基礎 select() color 第一個 命名空間 先來看命名空間吧; 命名空間是學習TP的基礎, <?php namespace app\lian\c1; class yi{ public $obj = "這是第一個

MongoDB學習筆記

.get 條件過濾 條件 $set system.in ins version tle 不存在 一、Mongodb命令 說明:Mongodb命令是區分大小寫的,使用的命名規則是駝峰命名法。 對於database和collection無需主動創建,在插入數據時,如果dat

【轉】Nodejs學習筆記--- 簡介及安裝Node.js開發環境

ack 目錄 javascrip 難度 時間 網站開發 clas jetbrains 常用 目錄 學習資料 簡介 安裝Node.js npm簡介 開發工具 Sublime Node.js開發環境配置 擴展:安裝多版本管理器 學習資料   1.深入淺出Node.j