`
天梯梦
  • 浏览: 13733609 次
  • 性别: Icon_minigender_2
  • 来自: 洛杉矶
社区版块
存档分类
最新评论

Node.js: 如何继承 events 自定义事件及触发函数

 
阅读更多

555

 

events 是node.js的核心api ,几乎大部分node.js 的api都继承 events 类(javascript中没有类,也不存在继承,确切说是模拟类和继承,点击查看)

比如我们常见的 http , stream ,fs .....等等.

 

因为node.js的实现就是异步非阻塞io,通过事件轮询触发异步回调的机制,在单线程运行模式下,合理应用服务器资源才是制胜法宝,正是因为事件轮询才使得异步IO在高并发处理下游刃有余,所以大部分的包去继承 events 似乎合情合理.

 

下面我们可以看一个常见的事件处理,但是我们用的时候似乎并没有当回事:

var req = http.request(params, function(res) {
    res.on("data", function(data) {
        console.log("response data", data);
    });
    res.on("end", function() {
         console.log("response end");
    });
});
req.end();

 

上面是一个标准的异步模式,而作为单线程的node.js绝对不会选择等待,那这个直接在node.js是如何处理的.

node.js运行在单线程模式下,但是可以有多个进程来处理,我们假设A进程执行api操作,B进程负责事件轮询.那么A调用上面的代码会马上得到一个结果,结果内容就是:"你的请求已经受理了" 然后A进程接着处理后面排队的其他api.

 

这里来一个小插曲:

" 如果是其他同步语言,会这样处理,执行到上面的代码以后会得得到什么结果? 什么也没有,只能一直在这里站着等待结果....后面的api也全部排队等待中ing.....突然A大声喊道"有结果了",这一声差点把睡着的api吓 尿,然后它拿起结果屁颠屁颠跑了,接着下一个api来请求.....

所以同步语言该如何解决这种资源浪费? 多开几个窗口,大家分散在不同窗口排队(这就是多线程) 然后各个线程要互相通报状态保持数据同步等....而node.js就避免了这种顾虑"

我们从插曲回来

上面的api调用后 A马上告知它结果,但是这个结果并不是它想要的.

于是B进程该上场表现了,它手里拿着一大串事件处理函数的引用.

当它发现了 "data" 事件,马上把 "data" 事件对应的处理函数引用给了"data"事件,

同理当它遇到 "end" 事件,马上把 "end"事件处理函数塞给了"end" ,

当某个事件执行完返回数据时马上交给B,而B再大声通知刚才调用的api,"你的业务逻辑数据返回来了",

这个可能刚才那个请求api已经吃了个盖饭,正在悠然的抽着烟,然后很娴熟的掐掉烟头,跑回去拿到了自己业务逻辑所需要的数据.

 

从上面描述可以看到,api在调用过程中一共拿到了2个结果:

第一个就是把代码提交进程A的时候,A马上给它返回一个结果"你的请求已经受理",虽然这个结果对业务没啥作用,但是对于api是有用的,它得知这个通知后,就不需要等待了.自己出去吃饭抽烟该干啥干啥去.

 

第二个得到的结果才是真正数据处理完以后的结果,这部分数据可能业务逻辑非常需要.

其中拿到第二个结果的过程中,B进程手提事件绑定函数,四处奔波寻找事件.

 

这是一个什么过程,就是当事件被触发时,就马上执行事件绑定函数.所以前提是:首先有事件绑定函数,其次注册了事件,(所以上面会提到B进程手里拿着事件绑定函数坐等事件)

 

看来要使用事件,首先我们需要有事件绑定函数,其次需要注册事件,而在node.js中 events 核心库正好实现了这几个api

 

events.EventEmitter 类提供了如下api

 

1.事件绑定函数

emitter.on(event, function(){
    //业务处理
});

还有另外一种绑定函数的方法,很不常用,和上面的等价

emitter.addListener(event,function(){
    //业务处理
});

 

2.绑定一次性函数,和上面的一样,给某个事件绑定一个函数,不同的是,对此事件只监听一次,也就是说,这个绑定函数只运行一次.

emitter.once(event,function(){
    //业务处理
});

 

3.移除一个事件绑定函数

emitter.removeListener(event,function(){
    //移除指定事件
});

 

4.移除所有绑定事件函数,注意参数是数组,数组元素是事件名称

emitter.removeAllListener([event,...]);

 

5.设置事件绑定函数上限,

node.js 建议我们在某个事件上的绑定函数不要超过10个,如果达到这个上限会予以警告,如何消除这个警告?用下面的api

emitter.setMaxListeners(n); //这样一个事件最多可以绑定n个函数

 

6.事件发射器,注册事件

emitter.emit(event,[arg1],[arg2])

用这个api注册事件,也就是自定义事件.

 

剩下的 几个api不一一列举了.

如何在一个自定义的类里使用事件? 答案是: 继承!

让你定义的类继承 events ,然后就可以使用上面的api了.

来一个实际的示例.一个SNS社区,有博客,问答,小组等模块,每个模块都有用户数据入口,比如 用户写博客要保存, 提问一个问题也要保存,在小组发表一个话题也要保存.

期间,不论我保存博客,问题还是小组话题,我都需要把数据写入数据库,统计个板块内容数量,统计用户发内容的数量.

 

如果我创建博客类,问答类,小组话题类,然后每个类再实现上面功能,这是一个重复且耗时的过程.这个应用场景就非常适合事件,重复且调用频繁

 

 

简单的框架:1414

eventTest 是这个示例的项目文件夹

methord 为逻辑应用层(或者为方法层)  //处理业务逻辑 ,调用 模型层实体对象的方法

model     为模型层(里面有一个父类 _base.js 和若干个子类,暂时只有一个blogInfo.js 博客类)  //个性化定义模型 属性,方法,事件

app.js     启动文件 //启动服务器,解析路由,调用方法层api (不做任何业务逻辑处理, 调用 --> 输出给用户 )

愿景:

有没有一种可能,我创建一个公用基础类_base,此类有一个工厂方法onEvent, onEvent专门用来绑定事件函数.

还有另外一个工厂方法emitEvent, emitEvent 专门用来注册发射事件.

 

代码实现:

var events=require('events');
var util=require('util');

function _base(){
	this.emitter=new events.EventEmitter(this);
};

util.inherits(_base,events.EventEmitter); //继承

_base.prototype.onEvent=function(eventName,callback){
	this.emitter.on(eventName,callback);
}

_base.prototype.emitEvent=function(eventName,arg){
	this.emitter.emit(eventName,arg);
}


module.exports=_base;

 

注意: node.js 中实现继承要使用工具类 util 中的 inherits 方法,下一篇博文专门用来讲此继承方式

model 实体层:

博客类 blogInfo   --> 继承自上面 _base 基础类

小组类 groupInfo  --> 继承自上面 _base 基础类

问答类 askInfo  --> 继承自上面 _base 基础类

我们只用 blogInfo 来举例说明,其他2个类大同小异:

因为blogInfo 继承了 _base 类,所以它也有了2个工厂方法,因为针对不同的类,可能需要发射不同的事件,定义不同的事件监听函数.

 

我们想实现在博客保存的时候, 内容提交到数据库,统计板块数量,统计用户内容数量,保存结束.

所以我们把个性化事件及事件绑定函数放在此类里定义:

var _base=require('./_base');
var util=require('util');
function blogInfo(){
    this.base=new _base();
}

util.inherits(blogInfo,_base);

blogInfo.prototype.onSave=function(blog){
	this.base.onEvent('saveStart',function(blog){
		console.log('saveStart',blog);
	});

	this.base.onEvent('blogCount',function(blog){
		console.log('blogCount',blog);
	});

	this.base.onEvent('userInfoCount',function(blog){
		console.log('count',blog);
	});

	this.base.onEvent('saveEnd',function(blog){
		console.log('saveEnd',blog);
	});
};

blogInfo.prototype.emitEvent=function(blog){

	this.base.emitEvent('saveStart',blog);

	this.base.emitEvent('blogCount',blog);

	this.base.emitEvent('userInfoCount',blog);

	this.base.emitEvent('saveEnd',blog);
};

 

上面的blogInfo 继承了 _base ,然后在原型对象上定义方法onSave , onSave 方法里调用父类的 onEvent 工厂方法分别给4个事件, saveStart ,blogCount, userInfoCount , saveEnd  定义了对应事件的绑定函数.

 

接着blogInfo 在原型对象上定义了方法 emitEvent 方法,并在方法里发射了4个事件 saveStart ,blogCount, userInfoCount , saveEnd

其他模型类似blogInfo的定义,(小组话题,问答等,有兴趣自己实现)

方法层定义一个blog的业务处理逻辑块:

var BlogInfo=require('../model/blogInfo');


exports.blog_save=function(newblog){

	var blogInfo=new BlogInfo();

	blogInfo.onSave(newblog);

	blogInfo.emitEvent(newblog);
};

 

很简单的功能,就是创建博客实体对象,把新博客数据调用 onSave 方法让4个事件先监听好(4个观察者,坐等事件发生)

 

然后再调用 事件发射器把事件注册,(注意,一定要先又事件监听函数,然后出发事件,才有效果,否则事件发射结束,你无路如何也执行不了事件绑定函数,所以上面代码调用顺序绝对不能反)

app.js  代码启动文件

var http = require('http');        
var blog= require('./methord/blog');


var webServer = function (req, res){ 
	if(req.url!='/favicon.ico'){
		var newblog={title:"标题",content:"内容"};
		blog.blog_save(newblog);

		res.writeHead(200, {'Content-Type': 'text/html;charset=utf-8'}); 
		res.write('<html><body>'); 
		res.write('<h1>*** save blog ***</h1>'); 
		res.write('<h2>Hello!</h2>'); 
		res.end('</body></html>'); 
	}
};

var createWebServer=http.createServer(webServer);

createWebServer.listen(8000);
console.log('listen 8000');

 

一个不能再简单的node.js 服务器端实现,没有路由匹配.....此demo只在实现事件发射及相关绑定函数.

因为node.js默认一个request 总是会请求2次 why? 不明白的点链接查看.所以我在路由里简单加了个 if 判断.

不论什么请求,我们都能模拟一个 保存blog的情形.因为保存我们绑定了4个监听函数,然后触发保存方法的一刹那,我们会发射4个事件,这是事件观察者(监听函数)会以迅雷不及掩耳之势去捕捉,然后调用绑定函数帮我们实现了4个愿景..... 看下输出的结果吧:

 

页面输出结果,精美UI亮瞎你的双眼!!!1212

控制台捕获事件的结果怎么样?

 

1111

 

4个函数监听器各负其职,监听到了事件,而且成功执行了事件绑定函数.

*****************END*****************

 

原文: http://yijiebuyi.com/blog/1a8cb4bf8510f8e9267c2873b4cdda33.html

本文转自:Node.js: 如何继承 events 自定义事件及触发函数

 

 

 

 

 

 

 

 

 

 

 

 

 

 

分享到:
评论

相关推荐

    node.js api

    util是Node.js的内置工具模块,提供了常用函数的集合,比如格式化、调试、日志记录、对象检查、继承等。 ### Events事件 Node.js异步事件驱动的特点,使它内建了事件循环和事件发射器机制。 - **events....

    nnode.rar(node.js)

    6. `events`:事件触发和监听机制,是Node.js的基础。 除了核心模块,Node.js还有大量的第三方模块,可以通过npm(Node Package Manager)进行安装和管理。npm是世界上最大的开源库生态系统,拥有数万个可供使用的...

    从Node.js事件触发器到Vue自定义事件的深入讲解.docx

    本文主要讨论了从Node.js中的事件触发器到Vue框架中的自定义事件的原理和应用,帮助开发者深入理解这两者之间的关联。 首先,让我们从Node.js的事件触发器开始。Node.js提供了一个名为`EventEmitter`的内置模块,它...

    Node.js:我的一些node.js代码

    Node.js是一种基于Chrome V8引擎的JavaScript运行环境,它允许开发者使用JavaScript进行服务器端编程,打破了传统的前端后端界限。这个“Node.js:我的一些node.js代码”项目可能包含了一系列用Node.js编写的示例代码...

    《深入浅出Node.js》:Node异步编程解决方案之事件发布-订阅模式.docx

    《深入浅出Node.js》这本书深入探讨了Node.js的异步编程解决方案,特别是事件发布-订阅模式。在Node.js中,异步编程是其核心特性,它利用非阻塞I/O和事件驱动机制来提高性能,避免了多线程带来的复杂性。异步编程的...

    Node.js快速学习入门

    Node.js 提供了一个事件模块,可以用来监听和触发事件。例如,创建一个监听键盘事件的例子: ```javascript const events = require('events'); const eventEmitter = new events.EventEmitter(); eventEmitter.on...

    node.JS事件机制与events事件模块的使用方法详解

    这些方法接收两个参数:事件名称和监听器函数。 ```javascript emitter.on('test', function() { console.log('监听到test事件'); }); ``` 3. **触发事件**: `emit`方法用于触发指定的事件,它可以传递任意...

    Node.js中使用事件发射器模式实现事件绑定详解

    Node.js中的事件发射器模式是一种基于发布/订阅机制的设计模式,它允许开发者订阅感兴趣的事件,并在这些事件被触发时执行相应的回调函数。这种模式在Node.js的很多内置对象中都有应用,例如HTTP服务器或文件系统...

    Node.js服务端编程

    - Node.js基于事件驱动模型,这意味着所有的异步操作都在完成后通过事件通知的形式触发回调函数。这种方式极大地提高了处理并发请求的能力。 - **事件循环**:Node.js的核心机制之一,负责监控事件队列,并在适当...

    node.js笔记.zip

    2. **核心模块**:Node.js内置了一些核心模块,如`fs`(文件系统)用于读写文件,`http`和`https`用于创建HTTP/HTTPS服务器,`path`用于处理文件路径,`util`提供通用的工具函数,`events`用于事件触发和监听。...

    node.js手册中文版

    Node.js是一个基于Chrome V8引擎的JavaScript运行环境,允许开发者使用JavaScript编写服务器端应用。Node.js利用事件驱动、非阻塞I/O模型,使其轻量又高效,非常适合构建高性能、可扩展的网络应用。 #### 全局对象...

    从Node.js事件触发器到Vue自定义事件的深入讲解

    这篇文章深入探讨了从Node.js的事件触发器到Vue自定义事件的概念和应用,旨在帮助读者理解和掌握这两种事件机制。在Node.js中,事件模块`EventEmitter`是处理事件的核心,它提供了`on`和`emit`两个关键方法。`on`...

    Node.js-Camo-基于Class的ES6ODM用于类似于Mongo的数据库

    6. **事件(Events)**:在数据操作前后,Camo可以触发事件,让开发者可以在合适的时间点执行额外的逻辑。 7. **插件系统(Plugin System)**:Camo可能有一个插件系统,允许扩展其功能以满足特定需求。 在"Camo-...

    Node.js设计与使用.pdf

    事件机制则是通过内置的`events`模块实现,EventEmitter类允许创建事件发射器,用于触发和监听事件,从而实现松耦合的组件通信。 总的来说,Node.js是一个适合快速开发网络应用的工具,尤其适用于高并发的IO密集型...

    Learnin_-Basic_-of_Node.js:从零开始的 Node.js 基础

    Node.js 是一个基于 Chrome V8 引擎的 JavaScript 运行环境,它让开发者能够在服务器端使用 JavaScript 编程,打破了 JavaScript 仅限于浏览器运行的传统。本教程将引导你从零开始学习 Node.js 的基础知识。 一、...

    node.js 代码

    Node.js 是一个基于 Chrome V8 引擎的 JavaScript 运行环境,它让开发者能够使用 JavaScript 来进行服务器端编程。Node.js 使用了一个事件驱动、非阻塞 I/O 模型,使其轻量又高效,非常适合构建数据密集型的实时应用...

    关于Node.js的events.EventEmitter用法介绍

    Node.js中使用事件驱动的方式进行编程,events模块提供了一个核心的功能,即EventEmitter类。这个类用于处理事件发射和监听,是实现Node.js事件驱动编程模式的基础。 EventEmitter的核心概念包括事件发射和事件监听...

Global site tag (gtag.js) - Google Analytics