Alex Liang

在新創公司擔任軟體工程師,記錄我的學習歷程

NodeJS Event Emitter介紹

NodeJS是以非同步事件驅動為導向的設計,而基本的事件要有發射端和接受端,以下做個介紹。

NodeJS有二種event: system event和custom event
前者為底層操作如檔案系統和網路協定,以C++為核心寫在libuv裡
後者是本文要介紹的event emitter

以下範例實做簡單的event emitter

app.js
1
2
3
4
5
6
7
8
9
10
11
12
13
var Emitter = require('./emitter');
var emtr = new Emitter();

emtr.on('greet', function() {
console.log('Hello, this is Alex');
});

emtr.on('greet', function() {
console.log('Thanks');
});

console.log('Hello');
emtr.emit('greet');
emitter.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
function Emitter() {
this.events = {};
}

Emitter.prototype.on = function(type, listener) {
this.events[type] = this.events[type] || [];
this.events[type].push(listener);
}

Emitter.prototype.emit = function(type) {
if (this.events[type]) {
this.events[type].forEach(function(listener) {
listener();
});
}
}

module.exports = Emitter;

在emitter.js中,我們先宣告Emitter,其中包含一個空的events property。
接著定義on,此為事件的接收端,每次有人呼叫on時,將listener加入陣列中;emit則是發射端(emitter在電子學裡為電晶體的發射極,沒想到會借用這個字)負責把同類型事件的listener都執行一次

而app.js一開始先定義’greet’這個event的二個listener,再來呼叫emit,最後的結果如下:

1
2
3
$ Hello
$ Hello, this is Alex
$ Thanks

從上例知道emitter的實作後,我們改用內建的events api來實作:

app.js
1
2
3
4
5
6
7
8
9
10
11
12
13
var Emitter = require('events');
var emtr = new Emitter();

emtr.on('greet', function() {
console.log('Hello, this is Alex');
});

emtr.on('greet', function() {
console.log('Thanks');
});

console.log('Hello');
emtr.emit('greet');

其實只要改成require內建的events即可。但這個程式還有一個問題:出現很多次’greet’這個magic string。我們可以使用config.js將其包裝:

config.js
1
2
3
4
5
module.exports = {
events : {
GREET: 'greet',
}
}
app.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
var Emitter = require('events');
var eventConfig = require('./config').events;

var emtr = new Emitter();

emtr.on(eventConfig.GREET, function() {
console.log('Hello, this is Alex');
});

emtr.on(eventConfig.GREET, function() {
console.log('Thanks');
});

console.log('Hello');
emtr.emit('greet');

如此一來,以後要加入/修改事件類型,只要改config.js就好,省去許多複製貼上和debug的時間。