NodeJS是以非同步事件驅動為導向的設計,而基本的事件要有發射端和接受端,以下做個介紹。
NodeJS有二種event: system event和custom event
前者為底層操作如檔案系統和網路協定,以C++為核心寫在libuv裡
後者是本文要介紹的event emitter
以下範例實做簡單的event emitter
app.js1 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.js1 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.js1 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.js1 2 3 4 5
| module.exports = { events : { GREET: 'greet', } }
|
app.js1 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的時間。