Node事件的監(jiān)聽與觸發(fā)的實現(xiàn)
Node.js是由事件驅(qū)動的,每個任務(wù)都可以當(dāng)作一個事件來處理,本貼將對Node.js中的events模塊及其中處理事件的類EventEmitter的使用進(jìn)行詳細(xì)講解。
1、EventEmitter對象
在JavaScript中,通過事件可以處理許多用戶的交互,比如鼠標(biāo)的單擊、鍵盤按鍵的按下、對鼠標(biāo)移動的反應(yīng)等。在Node.js中也提供了類似的事件驅(qū)動,主要是通過events模塊實現(xiàn)的,該模塊中提供了EventEmitter類,用于處理事件。要使用EventEmitter類處理事件,首先需要對其進(jìn)行初始化,代碼如下:
EventEmitter = require('events') eventEmitter = new EventEmitter()
在Node.js中,可以添加監(jiān)聽事件的對象都是繼承自EventEmitter對象,后者提供了用于處理Node.js事件的方法,常用方法及說明如下表所示:
說明
EventEmitter對象的addListener()方法和on()方法都用來添加監(jiān)聽事件,它們的使用是等效的,實際上,on方法在內(nèi)部實現(xiàn)時調(diào)用了addListener()方法。Node.js中推薦使用on()方法添加監(jiān)聽事件。
使用EventEmitter對象創(chuàng)建簡單事件,在WebStorm中創(chuàng)建一個.js文件,其中創(chuàng)建一個EventEmitter對象,并使用其on方法添加監(jiān)聽事件,在監(jiān)聽事件中輸出一個日志信息,然后使用emit()方法觸發(fā)該監(jiān)聽事件。代碼如下:
//引入events模塊 var events = require('events'); //生成EventEmitter對象 var custom = new events.EventEmitter(); //添加監(jiān)聽事件tick custom.on('tick', function (code) { console.log('執(zhí)行指定事件!'); }); //主動觸發(fā)監(jiān)聽事件tick custom.emit('tick');
運行程序,效果如下圖所示:
上面的代碼中,使用EventEmitter對象添加監(jiān)聽事件和觸發(fā)監(jiān)聽事件的代碼都放在了一個文件中,但實際應(yīng)用時,通常會把添加監(jiān)聽事件的模塊和觸發(fā)監(jiān)聽事件的模塊分開,如下圖所示就是一種常用的實現(xiàn)Node.js監(jiān)聽事件的文件構(gòu)成方式。其中,app.js文件中添加相關(guān)監(jiān)聽事件,rint.js文件中觸發(fā)相關(guān)監(jiān)聽事件。
演示項目中監(jiān)聽事件的添加與觸發(fā),程序開發(fā)步驟如下:
(1)在WebStorm中創(chuàng)建一個rint.js文件,該文件中使用EventEmitter對象的emit()方法每隔1秒觸發(fā)一次tick事件,代碼如下:
//定義變量,用來記錄執(zhí)行次數(shù) num=0 //引入events模塊 var events = require('events'); //生成 EventEmitter 對象 exports.timer = new events.EventEmitter(); //觸發(fā)監(jiān)聽事件tick setInterval(function () { num+=1 exports.timer.emit('tick',num); }, 1000);
(2)創(chuàng)建一個app.js文件,為rint模塊添加具體的tick事件,該事件中輸出一個日志信息,代碼如下:
//引入rint模塊 var rint = require('./rint.js'); //添加監(jiān)聽事件 rint.timer.on('tick', function (code) { console.log(`執(zhí)行第 $[code] 次監(jiān)聽事件`); });
運行app.js文件,效果如下圖所示:
2、添加和觸發(fā)監(jiān)聽事件
前面我們演示了如何在Node.js中添加監(jiān)聽事件和觸發(fā)監(jiān)聽事件,主要用到的是EventEmitter對象的on方法和emit方法,下面對這兩個方法及其使用進(jìn)行詳細(xì)講解。
2.1、 添加監(jiān)聽事件
通過上面的學(xué)習(xí),我們已經(jīng)知道,在Node.js中添加監(jiān)聽事件使用的是EventEmitter對象的on方法,該方法主要用來將回調(diào)函數(shù)添加到名為eventName的事件監(jiān)聽器數(shù)組的末尾,其語法格式如下:
on(eventName,listener)
- eventName:一個字符串,表示事件名稱。
- listener:回調(diào)函數(shù)。
在使用on方法向事件監(jiān)聽器數(shù)組中添加函數(shù)時,不會檢查其是否已被添加,如果多次調(diào)用并傳入相同的eventName與listener,會導(dǎo)致listener被重復(fù)添加多次。例如,下面代碼會為tick事件添加3次同樣的輸出日志函數(shù):
//引入events模塊 var events = require('events'); //生成EventEmitter對象 var custom = new events.EventEmitter(); //添加監(jiān)聽事件tick custom.on('tick', function () { console.log('第1次添加!'); }); custom.on('tick', function () { console.log('第2次添加!'); }); custom.on('tick', function () { console.log('第3次添加!'); }); //主動觸發(fā)監(jiān)聽事件tick custom.emit('tick');
執(zhí)行上面代碼時,默認(rèn)運行結(jié)果如下:
第1次添加!
第2次添加!
第3次添加!
從上面的運行結(jié)果可以看出,在默認(rèn)情況下,事件監(jiān)聽器會按照添加的順序依次調(diào)用,但如果想要改變添加順序,該怎么辦呢?EventEmitter對象提供了一個prependListener方法,該方法可以將事件回調(diào)函數(shù)添加到監(jiān)聽器數(shù)組的開頭,其語法如下:
prependListener(eventName, listener)
- eventName:一個字符串,表示事件名稱。
- listener:回調(diào)函數(shù)。
例如,將上面的代碼修改如下:
//引入events模塊 var events = require('events'); //生成EventEmitter對象 var custom = new events.EventEmitter(); //添加監(jiān)聽事件tick custom.on('tick', function () { console.log('第1次添加!'); }); //將回調(diào)函數(shù)添加到事件監(jiān)聽器數(shù)組的開頭 custom.prependListener('tick', function () { console.log('第2次添加!'); }); custom.on('tick', function () { console.log('第3次添加!'); }); //主動觸發(fā)監(jiān)聽事件tick custom.emit('tick');
運行結(jié)果會變成下面這樣:
第2次添加!
第1次添加!
第3次添加!
另外,需要注意的是,在上面的示例中,我們可以為同一個事件添加多個回調(diào)函數(shù),但如果添加的回調(diào)函數(shù)超過10個,則會出現(xiàn)如下圖所示的警告提示:
通過觀察上圖可以看到,如果為同一個事件添加的回調(diào)函數(shù)超過了10個,程序可以正常運行,但會在運行完之后出現(xiàn)警告提示,如何避免該警告呢?EventEmitter對象提供了一個setMaxListeners方法,該方法用來設(shè)置可以監(jiān)聽的最大回調(diào)函數(shù)數(shù)量,其語法格式如下:
setMaxListeners(limit)
- limit:一個數(shù)字,用來表示可以監(jiān)聽的最大回調(diào)函數(shù)數(shù)量。
例如,將監(jiān)聽器可以監(jiān)聽的最大回調(diào)函數(shù)數(shù)量設(shè)置為15個,代碼如下:
custom.setMaxListeners(15)
2.2、添加單次監(jiān)聽事件
使用前面介紹的on方法添加事件時,事件一旦添加就會一直存在,但如果遇到只想執(zhí)行一次監(jiān)聽事件的情況,使用on方法就無能為力了,這時可以使用EventEmitter對象的once方法,該方法用來將單次監(jiān)聽器listener添加到名為eventName的事件,當(dāng)eventName事件下次觸發(fā)時,監(jiān)聽器會先被移除,然后再調(diào)用。once方法的語法格式如下:
once(eventName,listener)
- eventName:一個字符串,表示事件名稱。
- listener:回調(diào)函數(shù)。
使用once方法添加單次監(jiān)聽事件:在WebStorm中創(chuàng)建一個index.js文件,其中使用EventEmitter對象的once方法為監(jiān)聽事件綁定一個回調(diào)函數(shù),然后使用emit方法觸發(fā)該監(jiān)聽事件,在觸發(fā)時,設(shè)置每秒觸發(fā)一次,代碼如下:
//引入events模塊 var events = require('events'); //生成EventEmitter對象 var custom = new events.EventEmitter(); function onUncaughtException(error) { //輸出異常內(nèi)容 console.log('發(fā)生異常,請多加小心 !'); } //添加監(jiān)聽事件event custom.once('event', onUncaughtException); //主動觸發(fā)監(jiān)聽事件event setInterval(function () { custom.emit('event'); }, 1000);
運行程序,效果如下圖所示:
說明
上圖中,使用once方法添加監(jiān)聽事件后,每隔一秒觸發(fā)一次該事件,但只執(zhí)行了一次。但是,如果將代碼中第10行的once修改為on,則運行結(jié)果會變成每隔一秒輸出一次日志。
2.3、觸發(fā)監(jiān)聽事件
當(dāng)對指定對象添加監(jiān)聽事件后,需要觸發(fā)添加的監(jiān)聽事件,這時需要使用EventEmitter對象的emit方法,其語法格式如下:
emit(eventName[, ...args])
- eventName:一個字符串,表示要觸發(fā)的事件名稱。
- args:回調(diào)函數(shù)中需要的參數(shù)。
- 返回值:布爾值,表示是否成功觸發(fā)事件。
使用emit方法觸發(fā)事件:在WebStorm中創(chuàng)建一個index.js文件,其中使用EventEmitter對象的on方法為監(jiān)聽事件綁定一個回調(diào)函數(shù),然后使用emit方法觸發(fā)該監(jiān)聽事件,代碼如下:
//引入events模塊 var events = require('events'); //生成EventEmitter對象 var custom = new events.EventEmitter(); //添加監(jiān)聽事件event custom.on('event', function listener() { console.log('觸發(fā)監(jiān)聽事件!'); }); //主動觸發(fā)監(jiān)聽事件event custom.emit('event');
運行程序,效果如下:
觸發(fā)監(jiān)聽事件!
上面為事件添加的回調(diào)函數(shù)沒有參數(shù),但在實際開發(fā)中,可能需要定義帶參數(shù)的回調(diào)函數(shù),這時使用emit方法觸發(fā)監(jiān)聽事件時,傳入相應(yīng)個數(shù)的參數(shù)即可。
觸發(fā)帶參數(shù)的監(jiān)聽事件:在WebStorm中創(chuàng)建一個index.js文件,其中使用EventEmitter對象的on方法為監(jiān)聽事件綁定兩個回調(diào)函數(shù),第一個回調(diào)函數(shù)有一個參數(shù),第二個回調(diào)函數(shù)的參數(shù)為不定長參數(shù),然后使用emit方法觸發(fā)該監(jiān)聽事件,代碼如下:
//引入events模塊 var events = require('events'); //生成EventEmitter對象 var custom = new events.EventEmitter(); //添加監(jiān)聽事件event custom.on('event', function listener1(arg) { console.log(`第 1 個監(jiān)聽器中的事件有參數(shù) ${arg}`); }); //添加監(jiān)聽事件event custom.on('event', function listener1(...args) { parameters = args.join(', '); //連接參數(shù) console.log(`第 2 個監(jiān)聽器中的事件有參數(shù) ${parameters}`); }); //主動觸發(fā)監(jiān)聽事件event custom.emit('event', 1, '明日','年齡:30','愛好:編程');
運行程序,效果如下圖所示:
從上圖可以看出,由于在第一個event事件中定義的回調(diào)函數(shù)中只有一個參數(shù)arg,因此在觸發(fā)時,即使傳入了多個值,其也只輸入第一個值;在第二個event事件定義的回調(diào)函數(shù)中,由于使用了“…args”進(jìn)行定義,這表示它是一個不定長參數(shù),因此在觸發(fā)時,會根據(jù)傳入?yún)?shù)的個數(shù)輸出相應(yīng)的內(nèi)容。
3、刪除監(jiān)聽事件
前面已經(jīng)學(xué)習(xí)了如何添加及觸發(fā)監(jiān)聽事件,如果添加的監(jiān)聽事件不需要了,可以將它刪除。刪除監(jiān)聽事件的方法如下:
- removeListener(eventName,listener):刪除指定名稱的監(jiān)聽事件。
- removeAllListeners([eventName]):刪除全部監(jiān)聽事件。
下面通過一個實例來演示如何使用Node.js中刪除監(jiān)聽事件的方法。將要添加到監(jiān)聽事件的回調(diào)函數(shù)單獨定義,并添加到event監(jiān)聽事件并觸發(fā);在觸發(fā)監(jiān)聽事件后,使用removeListener方法刪除該監(jiān)聽事件,并通過輸出刪除前后的監(jiān)聽事件名稱進(jìn)行對比。代碼如下:
//引入events模塊 var events = require('events'); //生成EventEmitter對象 var custom = new events.EventEmitter(); function listener() { console.log('觸發(fā)監(jiān)聽事件!'); } //添加監(jiān)聽事件event custom.on('event', listener); //主動觸發(fā)監(jiān)聽事件event custom.emit('event'); console.log(custom.eventNames()); //輸出刪除前的監(jiān)聽事件名稱 custom.removeListener('event',listener) ; //刪除event事件 console.log(custom.eventNames()); //輸出刪除后的監(jiān)聽事件名稱
說明
在EventEmitter中還提供了off(eventName, listener)方法,該方法實際上相當(dāng)于removeListener方法的別名,也可以刪除指定名稱的監(jiān)聽事件,其使用方法與removeListener完全一樣。運行程序,效果如下圖所示:
在使用removeListener方法刪除監(jiān)聽事件時,如果同一個事件監(jiān)聽器被多次添加到指定eventName的監(jiān)聽器數(shù)組中,則必須多次調(diào)用removeListener方法才能刪除所有事件。例如:
//引入events模塊 var events = require('events'); //生成EventEmitter對象 var custom = new events.EventEmitter(); function listener() { console.log('觸發(fā)監(jiān)聽事件!'); } //添加監(jiān)聽事件event custom.on('event', listener); /*多次添加同一個事件*/ custom.on('event', listener); custom.on('event', listener); custom.on('event', listener); //主動觸發(fā)監(jiān)聽事件event custom.emit('event'); console.log(custom.eventNames()); //輸出刪除前的監(jiān)聽事件名稱 custom.removeListener('event',listener); //刪除event事件 console.log(custom.eventNames()); //輸出刪除后的監(jiān)聽事件名稱
上面代碼中為event事件添加了4次listener回調(diào)函數(shù),但只使用removeListener刪除了一次event事件,運行結(jié)果如下圖所示:
觀察上圖可以看出,刪除前后,event事件都存在,說明使用removeListener并沒有完全刪除多次添加的event事件。這時,如果想要完全刪除event事件,可以使用removeListener方法刪除4次,也可以直接使用removeAllListeners刪除所有的監(jiān)聽事件,代碼如下:
custom.removeAllListeners('event'); //刪除所有event事件
到此這篇關(guān)于Node事件的監(jiān)聽與觸發(fā)的實現(xiàn)的文章就介紹到這了,更多相關(guān)Node事件監(jiān)聽與觸發(fā)內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
用npm install時報錯node-sass npm ERR command
在用npm install時報錯npm ERR! path D:…\node-sass和npm ERR! command failed 問題,本文給大家介紹了如何解決這個問題,文中通過圖文給大家介紹的非常詳細(xì),需要的朋友可以參考下2024-03-03Pycharm配置Node.js運行js代碼詳細(xì)過程
在PyCharm中寫JavaScript代碼并進(jìn)行調(diào)試是非常方便的,但是有些用戶可能對如何在PyCharm中準(zhǔn)確地運行JavaScript代碼感到困惑,這篇文章主要給大家介紹了關(guān)于Pycharm配置Node.js運行js代碼的相關(guān)資料,需要的朋友可以參考下2023-11-11使用Node.js腳本自動統(tǒng)計代碼量的實現(xiàn)代碼
手動統(tǒng)計代碼行數(shù)通常會耗費大量時間和精力,為了提高統(tǒng)計效率并減少人為錯誤,我們可以借助自動化工具來完成這項任務(wù),本文將介紹如何使用 Node.js 腳本來自動化統(tǒng)計項目代碼行數(shù),讓我們能夠輕松快捷地獲取項目的代碼量信息,需要的朋友可以參考下2023-12-12Node.js的HTTP模塊、URL模塊與supervisor工具介紹
這篇文章介紹了Node.js的HTTP模塊、URL模塊與supervisor工具,文中通過示例代碼介紹的非常詳細(xì)。對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下2022-06-06實例分析nodejs模塊xml2js解析xml過程中遇到的坑
這篇文章主要介紹了實例分析nodejs模塊xml2js解析xml過程中遇到的坑,涉及nodejs模塊xml2js解析xml過程中parseString方法參數(shù)使用技巧,需要的朋友可以參考下2017-03-03node 安裝 windows-build-tools全過程
這篇文章主要介紹了node 安裝 windows-build-tools全過程,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2022-10-10