Node中的Events模塊介紹及應(yīng)用
Node 中的 Events
Node 的 Events 模塊只定義了一個(gè)類(lèi),就是 EventEmitter(以下簡(jiǎn)稱(chēng) Event ),這個(gè)類(lèi)在很多 Node 本身以及第三方模塊中大量使用,通常是用作基類(lèi)被繼承。
在 Node 中,事件的應(yīng)用遍及代碼的每一個(gè)角落。
1. 事件和監(jiān)聽(tīng)器
Node 程序中的對(duì)象會(huì)產(chǎn)生一系列的事件,它們被稱(chēng)為事件觸發(fā)器(event emitter),例如一個(gè) HTTP Server 會(huì)在每次有新連接時(shí)觸發(fā)一個(gè)事件,一個(gè) Readable Stream 會(huì)在文件打開(kāi)時(shí)觸發(fā)一個(gè)事件等。
所有能觸發(fā)事件的對(duì)象都是 EventEmitter
類(lèi)的實(shí)例。EventEmitter
定義了 on
方法,該方法的聲明如下:
emitter.on(eventName, listener) eventName <String> | <Symbol> The name of the event. listener <Function> The callback function
on
方法接受兩個(gè)參數(shù):需要監(jiān)聽(tīng)的事件的名稱(chēng),當(dāng)事件觸發(fā)時(shí)需要調(diào)用的函數(shù)。因?yàn)?EventEmitter
是接口,從 EventEmitter
繼承的類(lèi)需要使用 new
關(guān)鍵字來(lái)構(gòu)造。
觸發(fā)事件監(jiān)聽(tīng)器很簡(jiǎn)單,只要調(diào)用 EventEmitter
實(shí)例的 emit
方法就行了。需要注意的是,這些事件是針對(duì)某個(gè)實(shí)例的,不存在全局的事件。當(dāng)你調(diào)用 on
方法的時(shí)候,需要綁定在特定的基于 EventEmitter
的對(duì)象上。EventEmitter
類(lèi)不同的實(shí)例之間也不會(huì)共享事件。
下面是一個(gè)事件注冊(cè)和觸發(fā)事件的例子。
const eventEmitter = require('events'); const myEmitter = new eventEmitter(); myEmitter.on('begin', () => { console.log('begin'); }); myEmitter.emit('begin');
上面的代碼中,首先初始化了一個(gè) EventEmitter
實(shí)例,然后注冊(cè)了一個(gè)名為 begin
的事件,之后調(diào)用 emit
方法觸發(fā)了這一事件。
用戶可以注冊(cè)多個(gè)同名的事件,在上面的例子中,如果注冊(cè)兩個(gè)名為 begin
的事件,那么它們都會(huì)被觸發(fā)。
如果想獲取當(dāng)前的 emitter
一共注冊(cè)了哪些事件,可以使用 eventNames
方法。
console.log(myEmitter.eventNames());
該方法會(huì)輸出包括全部事件名稱(chēng)的數(shù)組。就算注冊(cè)了兩個(gè)同名的 event
,輸出結(jié)果也只有一個(gè),說(shuō)明該方法的結(jié)果集并不包含重復(fù)結(jié)果。
2. 處理 error 事件
由于 Node 代碼運(yùn)行在單線程環(huán)境中,那么運(yùn)行時(shí)出現(xiàn)的任何錯(cuò)誤都有可能導(dǎo)致整個(gè)進(jìn)程退出。利用事件機(jī)制可以實(shí)現(xiàn)簡(jiǎn)單的錯(cuò)誤處理功能。
當(dāng) Node 程序出現(xiàn)錯(cuò)誤的時(shí)候,通常會(huì)觸發(fā)一個(gè)錯(cuò)誤事件,如果代碼中沒(méi)有注冊(cè)相應(yīng)的處理方法,會(huì)導(dǎo)致 Node 進(jìn)程崩潰退出。例如:
myEmitter.emit("error", new Error("crash!"));
上面的代碼主動(dòng)拋出了一個(gè) emor
,相當(dāng)于:
throw new Error ("crash");
如果我們不想因?yàn)閽伋鲆粋€(gè) error
而使進(jìn)程退出,那么可以讓 uncaughtException
事件作為最后一道防線來(lái)捕獲異常。
const eventEmitter = require('events'); const myEmitter = new eventEmitter(); process.on('uncaughtException', () => { console.log('got error'); }); throw new Error('Error occurred');
這種錯(cuò)誤處理的方式雖然可以捕獲異常,避免了進(jìn)程的退出,但不值得提倡。
關(guān)于其常見(jiàn)的方法如下:
emitter.addListener/on(eventName, listener)
:添加類(lèi)型為eventName
的監(jiān)聽(tīng)事件到事件數(shù)組尾部emitter.prependListener(eventName, listener)
:添加類(lèi)型為eventName
的監(jiān)聽(tīng)事件到事件數(shù)組頭部emitter.emit(eventName[, ...args])
:觸發(fā)類(lèi)型為eventName
的監(jiān)聽(tīng)事件emitter.removeListener/off(eventName, listener)
:移除類(lèi)型為eventName
的監(jiān)聽(tīng)事件emitter.once(eventName, listener)
:添加類(lèi)型為eventName
的監(jiān)聽(tīng)事件,以后只能執(zhí)行一次并刪除emitter.removeAllListeners([eventName])
: 移除全部類(lèi)型為eventName
的監(jiān)聽(tīng)事件
3. 繼承 Events 模塊
在實(shí)際的開(kāi)發(fā)中,通常不會(huì)直接使用 Event 模塊來(lái)進(jìn)行事件處理,而是選擇將其作為基類(lèi)進(jìn)行繼承的方式來(lái)使用 Event,在 Node 的內(nèi)部實(shí)現(xiàn)中,凡是提供了事件機(jī)制的模塊,都會(huì)在內(nèi)部繼承 Event 模塊。
4. 手寫(xiě) EventEmitter
下面我們來(lái)看看如何手寫(xiě)一個(gè) EventEmitter
。
class EventEmitter { constructor() { this.events = {}; } on(type, handler) { if (!this.events[type]) { this.events[type] = []; } this.events[type].push(handler); } addListener(type, handler) { this.on(type, handler) } prependListener(type, handler) { if (!this.events[type]) { this.events[type] = []; } this.events[type].unshift(handler); } removeListener(type, handler) { if (!this.events[type]) { return; } this.events[type] = this.events[type].filter(item => item !== handler); } off(type, handler) { this.removeListener(type, handler) } emit(type, ...args) { this.events[type].forEach((item) => { Reflect.apply(item, this, args); }); } once(type, handler) { this.on(type, this._onceWrap(type, handler, this)); } _onceWrap(type, handler, target) { const state = { fired: false, handler, type, target }; const wrapFn = this._onceWrapper.bind(state); state.wrapFn = wrapFn; return wrapFn; } _onceWrapper(...args) { if (!this.fired) { this.fired = true; Reflect.apply(this.handler, this.target, args); this.target.off(this.type, this.wrapFn); } } }
到此這篇關(guān)于Node中的Events事件介紹及應(yīng)用的文章就介紹到這了,更多相關(guān)Node Events內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Node.js如何自動(dòng)審核團(tuán)隊(duì)的代碼
在項(xiàng)目開(kāi)發(fā)中,統(tǒng)一團(tuán)隊(duì)的代碼風(fēng)格很重要,本文介紹如何用Node.js來(lái)自動(dòng)審核,來(lái)提高您的開(kāi)發(fā)速度。2016-07-07gyp?ERR!報(bào)錯(cuò)問(wèn)題解決辦法
這篇文章主要給大家介紹了關(guān)于gyp?ERR!報(bào)錯(cuò)問(wèn)題的解決辦法,文中將解決的辦法介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2024-01-01詳解NodeJS Https HSM雙向認(rèn)證實(shí)現(xiàn)
這篇文章主要介紹了詳解NodeJS Https HSM雙向認(rèn)證實(shí)現(xiàn),小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2019-03-03node.js微信小程序配置消息推送的實(shí)現(xiàn)
這篇文章主要介紹了node.js微信小程序配置消息推送的實(shí)現(xiàn),小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2019-02-02node+koa+canvas繪制出貨單、收據(jù)票據(jù)的方法
在生成票據(jù)需求中,我們會(huì)想到前端生成或者后端生成返回圖片地址訪問(wèn)兩個(gè)方法,前端生成則不需要調(diào)用接口,而后端是在完成整個(gè)流程時(shí)就進(jìn)行生成然后把上傳的地址保存數(shù)據(jù)庫(kù),這篇文章主要介紹了node+koa+canvas繪制出貨單,收據(jù),票據(jù),需要的朋友可以參考下2022-09-09初識(shí)NodeJS服務(wù)端開(kāi)發(fā)入門(mén)(Express+MySQL)
本篇文章主要介紹了初識(shí)NodeJS服務(wù)端開(kāi)發(fā)入門(mén)(Express+MySQL),可以對(duì)數(shù)據(jù)庫(kù)中的一張表進(jìn)行簡(jiǎn)單的CRUD操作,有興趣的可以了解一下。2017-04-04