1. 程式人生 > >nodejs事件的監聽與事件的觸發

nodejs事件的監聽與事件的觸發

一、事件機制的實現

Node.js中大部分的模組,都繼承自Event模組(http://nodejs.org/docs/latest/api/events.html )。Event模組(events.EventEmitter)是一個簡單的事件監聽器模式的實現。具有addListener/on,once,removeListener,removeAllListeners,emit等基本的事件監聽模式的方法實現。它與前端DOM樹上的事件並不相同,因為它不存在冒泡,逐層捕獲等屬於DOM的事件行為,也沒有preventDefault()、stopPropagation()、 stopImmediatePropagation() 等處理事件傳遞的方法。

   從另一個角度來看,事件偵聽器模式也是一種事件鉤子(hook)的機制,利用事件鉤子匯出內部資料或狀態給外部呼叫者。Node.js中的很多物件,大多具有黑盒的特點,功能點較少,如果不通過事件鉤子的形式,物件執行期間的中間值或內部狀態,是我們無法獲取到的。這種通過事件鉤子的方式,可以使程式設計者不用關注元件是如何啟動和執行的,只需關注在需要的事件點上即可。

二、事件觸發

events 模組只提供了一個物件: events.EventEmitter。EventEmitter的核心就是事件發射與事件監聽器功能的封裝。EventEmitter的每個事件由一個事件名和若干個引數組成,事件名是一個字串,通常表達一定的語義。對於每個事件,EventEmitter支援若干個事件監聽器。當事件發射時,註冊到這個事件的事件監聽器被依次呼叫,事件引數作為回撥函式引數傳遞。

讓我們以下面的例子解釋這個過程:

//引入事件模組
var events = require("events");

//建立事件監聽的一個物件
var  emitter = new events.EventEmitter();

//監聽事件some_event
emitter.addListener("some_event",function(){
    console.log("事件觸發,呼叫此回撥函式");
});

//觸發事件some_event
emitter.emit("some_event");

執行結果:事件觸發,呼叫此回撥函式

var events = require('events');
var emitter = new events.EventEmitter();
emitter.on('someEvent', function(arg1, arg2) {
console.log('listener1', arg1, arg2);
});
emitter.on('someEvent', function(arg1, arg2) {
console.log('listener2', arg1, arg2);
});
emitter.emit('someEvent', 'byvoid', 1991);

執行的結果是:

listener1 byvoid 1991

listener2 byvoid 1991

以上例子中,emitter 為事件 someEvent 註冊了兩個事件監聽器,然後發射了someEvent事件。執行結果中可以看到兩個事件監聽器回撥函式被先後呼叫。這就是EventEmitter最簡單的用法。接下來我們介紹一下EventEmitter常用的API。
 EventEmitter.on(event, listener) 為指定事件註冊一個監聽器,接受一個字串 event 和一個回撥函式listener。EventEmitter.emit(event, [arg1], [arg2], […]) 發射 event事件,傳遞若干可選引數到事件監聽器的引數表。
EventEmitter.once(event, listener) 為指定事件註冊一個單次監聽器,即監聽器最多隻會觸發一次,觸發後立刻解除該監聽器。
 EventEmitter.removeListener(event, listener) 移除指定事件的某個監聽器,listener 必須是該事件已經註冊過的監聽器。
 EventEmitter.removeAllListeners([event]) 移除所有事件的所有監聽器,如果指定 event,則移除指定事件的所有監聽器。
更詳細的 API 文件參見 http://nodejs.org/api/events.html

想想其實跟jquery自定義事件很相似:

//給element繫結hello事件
element.on("hello",function(){
  alert("hello world!");
});
//觸發hello事件
element.trigger("hello");

三、事件機制的進階應用

繼承event.EventEmitter

實現一個繼承了EventEmitter類是十分簡單的,以下是Node.js中流物件繼承EventEmitter的例子:

var util = require("util");

var events = require("events");

//建立構造事件物件的建構函式
function Stream(){
    events.EventEmitter.call(this);
}
util.inherits(Stream, events.EventEmitter);

//例項建立事件監聽的一個物件
var elem = new Stream();

//監聽事件
elem.addListener("one_event",function(){
    console.log("事件觸發,呼叫此回撥函式");
});

//觸發事件some_event
elem.emit("one_event");

一個經典的事件監聽觸發,程序通訊例子:

master.js

var childprocess = require('child_process');
var worker = childprocess.fork('./worker.js');

console.log('pid in master:', process.pid);

//監聽事件
worker.on('message', function(msg) {
  console.log('1:', msg);
})
process.on('message', function(msg) {
  console.log('2:', msg);
})

worker.send('---');

//觸發事件 message
process.emit('message', '------');

worker.js

console.log('pid in worker:', process.pid);

process.on('message', function(msg) {
  console.log('3:', msg);
});

process.send('===');
process.emit('message', '======');
$ node master.js


pid in master: 22229      // 主程序建立後列印其 pid
2: ------                 // 主程序收到給自己發的訊息
pid in worker: 22230      // 子程序建立後列印其 pid
3: ======                 // 子程序收到給自己發的訊息 
1: ===                    // 主程序收到來自子程序的訊息
3: ---                    // 子程序收到來自主程序的訊息

其中有兩個有趣的點:

在主程序中,使用 worker.on(‘message’, …) 監聽來自子程序的訊息,使用 process.on(‘message’, …) 監聽給自己發的訊息。但是在子程序中,只有 process.on(‘message’, …) 一種訊息監聽方式,無法區分訊息來源。

如果有給自己發訊息的情況,則必須將對應的訊息監聽的程式碼放在訊息傳送程式碼前面,否則無法監聽到該訊息傳送。例如將 master.js 的最後一行程式碼 process.emit(‘message’, ‘——‘); 放置到該檔案第一行,則執行結果不會輸出 2: ——。

如果不能控制訊息監聽程式碼和訊息傳送程式碼的先後順序,可將給自己傳送訊息的程式碼改寫為 setImmediate(process.emit.bind(process, ‘message’, {{message}}));

參考資料:

http://www.cnblogs.com/zhongweiv/p/nodejs_events.html(很多例項)

http://www.infoq.com/cn/articles/tyq-nodejs-event/

http://www.toolmao.com/nodejs-zhongwen-events-shijian

http://www.ynpxrz.com/n691854c2023.aspx

http://www.jb51.net/article/61079.htm

注:轉自這裡