初步揭秘node.js中的事件

 当你学习node.js的时候,Events是一个非常重要的需要理解的事情。非常多的Node对象触发事件,你能在文档API中找到很多例子。但是关于如何写自己的事件和监听,你可能还不太清楚。如果你不了解,你很快就会碰壁。那么我们如何写自己的事件和监听呢?首先而且重要的是,你要了解node.js中的events模块。

事件发布/订阅模式
事件监听器模式是一种广泛应用于一步变成的模式,是回调函数的事件化,又称发布/订阅模式。
Node自身提供的events模块,是发布/订阅模式的一个简单实现,Node中部分模块都继承自它,这个模块比前段浏览器中的大量DOM事件简单,不存在事件冒泡。它具有addListener/on(),once(),removeListener(),removeAllListeners(),emit()等基本的事件监听模式的方法实现。事件发布/订阅模式的操作极其简单:

//订阅
emitter.on("event1",function(message){
    console.log(message);
})
//发布
emitter.emit("event1","I'm message");

可以看到,订阅事件就是一个高阶函数的应用。事件发布/订阅模式可以实现一个事件多个回调函数的关联,这些回调函数又称为事件侦听器。通过emit()发布事件后,消息会立即传递给当前时间的所有侦听器执行。侦听器可以很灵活的添加和删除,使得事件和具体处理逻辑可以很轻松的关联和解耦。
事件发布/订阅模式自身并无同步和异步调用的问题,但在Node中,emit()调用多半是伴随事件循环而异步触发的,所以说事件发布/订阅广发应用于异步编程。

快速浏览

加载模块,添加下面这段代码到你的js文件
require("events");
require("events").EventsEmitter

特别的,上两句代码会告诉你,以后能发出事件的所有对象基本上都是后者的实例。让我们创建一个事件对象dummy吧!

dummy.js

//基础引入
var events = require('events');

// 以后会用到
module.exports = Dummy;

function Dummy() {
    events.EventEmitter.call(this);
}

// 继承 events.EventEmitter
Dummy.super_ = events.EventEmitter;
Dummy.prototype = Object.create(events.EventEmitter.prototype, {
    constructor: {
        value: Dummy,
        enumerable: false
    }
});

上面这段代码最终要的是,我们通过EventEmitter可以扩展自己的对象。并继承了,它所有的prototype objects,methods等等。

那么让我们假定,Dummy需要有个方法叫cooking()。如果你依照原文的话,最后肯定会报错cook不存在,所以依据原文注释我做了如下的修改。
cooking函数,功能输出我正在做...,做好之后触发事件,输出...很香!并想触发做好饭cooked事件。

Dummy.prototype.cooking=function(chicken){
    var self=this;
    self.chicken=chicken;
    self.cook=cook;
    self.cook(chicken,function(cooked_chicken){
        self.chicken=cooked_chicken;
        console.log(cooked_chicken);
        self.emit('cooked',self.chicken);
    })
    return self;
}

function cook(chicken,callback){
        console.log("I'm cooking"+chicken+" !");
        callback(chicken+" is fragrant!");
}

那么在主js中如何调用它呢?
dummy-node.js

var Dummy=require('./dummy');
var kenny=new Dummy();
var dinner=kenny.cooking("fried_chicken");
dinner.on('cooked',function(chicken){
console.log(chicken+" Put lunch on the table!");
});

这里给出的例子中,有一点值得注意,子类有点矫枉过正,以及使用events.EventEmitter之触发了一个事件一次。如果仅仅是低触发的事件或者只有事件个数少的话,你可能想采用新的方法,比如用异步函数。

提醒

如果对一个事件添加了超过10个侦听器,将会得到一条警告。这一处设计与Node自身单线程运行有关,设计者认为侦听器太多可能会导致内存泄露,所以存在这样一条警告。调用emmitter.setMaxListeners(0);可以将这个限制去掉。另一方面,由于事件发布会引起一系列侦听器执行,如果事件相关的侦听器过多,可能存在过多占用CPU的情景。
为了处理异常,EventEmitter对象对error事件进行了特殊对待。如果运行期间的错误出发了error事件,EventEmitter会检查是否有对error事件添加过侦听器。如果添加了这个错误将会交由该侦听器处理,否则这个错误将会作为异常抛出。如果外部没有捕获这个异常,将会引起线程退出。一个健壮的EventEmitter实例应该对error事件做处理。

 

示例下载

参考此文 http://howtonode.org/demystifying-events-in-node

 

posted @ 2014-01-04 22:06  易小亨  阅读(851)  评论(0编辑  收藏  举报