今天小編給大家分享一下Node中的Events模塊怎么應用的相關知識點,內容詳細,邏輯清晰,相信大部分人都還太了解這方面的知識,所以分享這篇文章給大家參考一下,希望大家閱讀完這篇文章后有所收獲,下面我們一起來了解一下吧。
Node 的 Events 模塊只定義了一個類,就是 EventEmitter(以下簡稱 Event ),這個類在很多 Node 本身以及第三方模塊中大量使用,通常是用作基類被繼承。
在 Node 中,事件的應用遍及代碼的每一個角落。
Node 程序中的對象會產生一系列的事件,它們被稱為事件觸發器(event emitter),例如一個 HTTP Server 會在每次有新連接時觸發一個事件,一個 Readable Stream 會在文件打開時觸發一個事件等。
所有能觸發事件的對象都是 EventEmitter 類的實例。EventEmitter 定義了 on 方法,該方法的聲明如下:
emitter.on(eventName, listener) eventName <String> | <Symbol> The name of the event. listener <Function> The callback function
on 方法接受兩個參數:需要監聽的事件的名稱,當事件觸發時需要調用的函數。因為 EventEmitter 是接口,從 EventEmitter 繼承的類需要使用 new 關鍵字來構造。
觸發事件監聽器很簡單,只要調用 EventEmitter實例的 emit 方法就行了。需要注意的是,這些事件是針對某個實例的,不存在全局的事件。當你調用 on 方法的時候,需要綁定在特定的基于 EventEmitter 的對象上。EventEmitter 類不同的實例之間也不會共享事件。
下面是一個事件注冊和觸發事件的例子。
const eventEmitter = require('events');
const myEmitter = new eventEmitter();
myEmitter.on('begin', () => {
console.log('begin');
});
myEmitter.emit('begin');上面的代碼中,首先初始化了一個 EventEmitter 實例,然后注冊了一個名為 begin 的事件,之后調用 emit 方法觸發了這一事件。
用戶可以注冊多個同名的事件,在上面的例子中,如果注冊兩個名為 begin 的事件,那么它們都會被觸發。
如果想獲取當前的 emitter 一共注冊了哪些事件,可以使用 eventNames 方法。
console.log(myEmitter.eventNames());
該方法會輸出包括全部事件名稱的數組。就算注冊了兩個同名的 event,輸出結果也只有一個,說明該方法的結果集并不包含重復結果。
由于 Node 代碼運行在單線程環境中,那么運行時出現的任何錯誤都有可能導致整個進程退出。利用事件機制可以實現簡單的錯誤處理功能。
當 Node 程序出現錯誤的時候,通常會觸發一個錯誤事件,如果代碼中沒有注冊相應的處理方法,會導致 Node 進程崩潰退出。例如:
myEmitter.emit("error", new Error("crash!"));上面的代碼主動拋出了一個 emor,相當于:
throw new Error ("crash");如果我們不想因為拋出一個 error 而使進程退出,那么可以讓 uncaughtException 事件作為最后一道防線來捕獲異常。
const eventEmitter = require('events');
const myEmitter = new eventEmitter();
process.on('uncaughtException', () => {
console.log('got error');
});
throw new Error('Error occurred');這種錯誤處理的方式雖然可以捕獲異常,避免了進程的退出,但不值得提倡。
關于其常見的方法如下:
emitter.addListener/on(eventName, listener) :添加類型為 eventName 的監聽事件到事件數組尾部
emitter.prependListener(eventName, listener):添加類型為 eventName 的監聽事件到事件數組頭部
emitter.emit(eventName[, ...args]):觸發類型為 eventName 的監聽事件
emitter.removeListener/off(eventName, listener):移除類型為 eventName 的監聽事件
emitter.once(eventName, listener):添加類型為 eventName 的監聽事件,以后只能執行一次并刪除
emitter.removeAllListeners([eventName]): 移除全部類型為 eventName 的監聽事件
在實際的開發中,通常不會直接使用 Event 模塊來進行事件處理,而是選擇將其作為基類進行繼承的方式來使用 Event,在 Node 的內部實現中,凡是提供了事件機制的模塊,都會在內部繼承 Event 模塊。
下面我們來看看如何手寫一個 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);
}
}
}以上就是“Node中的Events模塊怎么應用”這篇文章的所有內容,感謝各位的閱讀!相信大家閱讀完這篇文章都有很大的收獲,小編每天都會為大家更新不同的知識,如果還想學習更多的知識,請關注億速云行業資訊頻道。
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。