Nodejs學習筆記(二)--- 事件模組
目錄
簡介及資料
events是node.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(EventEmitter.on(event, listener) 示例原始碼'第一輪'); ee.emit('some_events', 'Wilson', 'Zhong'); console.log('第二輪'); ee.emit('some_events', 'Wilson', 'Z');
emitter.emit(event, [arg1], [arg2], [...])
var EventEmitter = require('events').EventEmitter; var ee = new EventEmitter(); ee.on(emitter.emit(event, [arg1], [arg2], [...]) 示例原始碼'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);
示例進行了三次觸發事件操作,其中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