node 事件机制
 
一 三种定时器
NodeJS中有三种类型的定时器:超时时间、时间间隔、即时定时器
1.超时时间:setTimeout(callback,delayMilliSeconds,[args])方法,如:
  1. setTimeout(myFunc,1000);
setTimeout函数返回一个定时器对象的ID,可以在delayMilliSeconds到期前的任何时候把此ID传递给clearTimeOut()来取消时间函数。
  1. var myTimeout=setTimeout(myFunc,1000);
  2. ...
  3. clearTimeOut(myTimeout);
2.时间间隔
  1. var myInterval=setInterval(myFunc,1000);
  2. ...
  3. clearInterval(myInterval);
3.即时器立即执行工作
即时计时器用来在I/O事件的回调函数开始执行后,但任何超时时间或时间间隔事件被执行之前,立即执行。
  1. var myImmediate=setImmediate(myFunc,1000);
  2. ...
  3. clearImmediate(myImmediate);

二 事件发射器和监听器

1.NodeJS事件模型的工作原理。
NodeJS不是在各个线程为每个请求执行所有的工作,它是把工作添加到事件队列中,然后有一个单独的线程运行一个事件循环把这个工作提取出来。事件循环抓取事件队列中最上面的条目,执行它,然后抓取下一个条目。当执行到长期运行或有阻塞I/O的代码时,它不是直接调用该函数,而是把函数虽同一个要在此函数完成后执行的回调函数一起添加到事件队列中。当NodeJS事件队列中的所有事件都被执行完成时,nodejs应用程序终止。
 
Node.js中,所有异步的I/O操作,在完成的时候都会发送一个事件到事件队列中。
Node.js中的许多对象也都会分发事件,比如:net.Server 对象会在每次有新链接时分发一个事件;fs.readStream 对象会在文件被打开的时候分发一个事件等等,所有这些产生事件的对象都是event.EventEmitter(事件监听/发射器)的实例。我们可以通过“ require('events') ”来访问该模块。
阻塞I/O停止当前线程的执行并等待一个回应,直到收到回应才能继续。nodejs使用事件回调来避免对阻塞I/O的等待。事件回调的关键就是事件轮询。
 
2.注册并发射自定义node.js事件
事件使用一个EventEmitter对象来发出,这个对象包含在events模块中,emit(eventName,[args])函数触发eventName事件,包括所提供的任何参数。
  1. var EventEmitter = require('events').EventEmitter; // 引入事件模块
  2. var event = new EventEmitter(); // 实例化事件模块
  3. // 注册事件(customer_event)
  4. event.on('customer_event', function() {
  5. console.log('customer_event has be occured : ' + new Date());
  6. });
  7. setInterval(function() {
  8. event.emit('customer_event'); // 发射(触发)事件
  9. }, 500);
使用EventEmitter对象的on注册事件,然后使用对象的emit发射事件。
 
3.EventEmitter介绍
events模块只提供了一个对象:events.EventEmitter。EventEmitter的核心就是事件发射与事件监听器功能的封装。
  1. var EventEmitter = require('events').EventEmitter; // 引入事件模块
  2. var event = new EventEmitter(); // 实例化事件模块
  3. // 注册事件(sayHello)
  4. event.on('sayHello', function(param1, param2) {
  5. console.log('Hello1 : ', param1, param2);
  6. });
  7.  
  8. // 再次注册事件(sayHello)
  9. event.on('sayHello', function(param1, param2) {
  10. console.log('Hello2 : ', param1, param2);
  11. });
  12. event.emit('sayHello', 'GuYing', '1996'); // 发射(触发)事件(sayHello)
注意到sayHello这个事件注册了两次。

EventEmitter的每一个事件都是由一个事件名和若干个参数组成。事件名是一个字符串,通常表达一定的语义。对于每个事件,EventEmitter支持若干个事件监听器。当事件发射时,注册到这个事件的事件监听器被依次调用,事件参数作为回调函数参数传递。
运行结果中可以看到两个事件监听器回调函数被先后调用。 这就是EventEmitter最简单的用法。
 
EventEmitter常用的API:
EventEmitter.on(event,listener)、emitter.addListener(event,listener)为指定事件注册一个监听器,接受一个字符串event和一个回调函数listener。
EventEmitter.once(event, listener) 为指定事件注册一个单次监听器,即监听器最多只会触发一次,触发后立刻解除该监听器。
EventEmitter.emit(event, [arg1], [arg2], [...]) 发射 event 事件,传递若干可选参数到事件监听器的参数表。
EventEmitter.removeListener(event, listener) 移除指定事件的某个监听器,listener必须是该事件已经注册过的监听器。
emitter.listeners(event)    返回这个事件的监听函数的数组
emitter.setMaxListeners(n)     设置这个emitter实例的最大事件监听数,默认是10个,设置0为不限制
emitter.removeAllListeners(event)      删除所有对这个事件的监听函数
 
举个简单的例子:
UserBean.js
  1. var events=require('events');
  2. var http=require('http');
  3. function UserBean(){
  4. //实例化事件模型
  5. this.eventEmit=new events.EventEmitter();
  6. this.zhuce=function(req,res){
  7. console.log('注册');
  8. req['uname']='aa';
  9. req['pwd']='bb';
  10. //触发事件
  11. this.eventEmit.emit('zhuceSuccess','aa','bb');
  12. },
  13. this.login=function(req,res){
  14. console.log('登录');
  15. res.write('用户名:'+req['uname']);
  16. res.write('密码:'+req['pwd']);
  17. res.write("登录");
  18. }
  19. }
  20. module.exports=UserBean;
event.js
  1. var http=require('http');
  2. var UserBean=require('./UserBean');
  3. http.createServer(function(request,response){
  4. response.writeHead(200,{'Content-Type':'text/html;charset=utf-8'});
  5. if(request.url!=='favicon.ico'){
  6. user=new UserBean();
  7. user.eventEmit.once('zhuceSuccess',function(uname,pwd){
  8. response.write('注册成功');
  9. console.log('传uname '+uname);
  10. console.log('传pwd '+pwd);
  11. user.login(request,response);
  12. response.end();
  13. });
  14. user.zhuce(request,response);
  15. }
  16. }).listen(8000);
  17. console.log('server running at http://127.0.0.1:8000/');

 4.error事件

EventEmitter 定义了一个特殊的事件 error,它包含了"错误"的语义,我们在遇到 异常的时候通常会发射 error 事件。
当 error 被发射时,EventEmitter 规定如果没有响应的监听器,Node.js 会把它当作异常,退出程序并打印调用栈。
我们一般要为会发射 error 事件的对象设置监听器,避免遇到错误后整个程序崩溃。例如:
  1. var events=require('events');
  2. var myEvent = new events.EventEmitter();
  3. myEvent.emit('error', new Error('whoops!'));
运行时会显示以下错误:
 

但是如果这么写就可以正确报错:
  1. var events=require('events');
  2. myEvent.on('error', (err) => {
  3. console.log('whoops! there was an error');
  4. });
  5. myEvent.emit('error', new Error('whoops!'));

5.注意
大多数时候我们不会直接使用 EventEmitter,而是在对象中继承它。包括 fs、net、 http 在内的,只要是支持事件响应的核心模块都是 EventEmitter 的子类。
为什么要这样做呢?原因有两点:
1)具有某个实体功能的对象实现事件符合语义, 事件的监听和发射应该是一个对象的方法。
2)JavaScript 的对象机制是基于原型的,支持 部分多重继承,继承 EventEmitter 不会打乱对象原有的继承关系。
Events(事件)模块是Node.js的核心,许多其他模块用它来围绕着事件架构功能。由于Node.js运行在单一的线程中,任何同步代码都是阻塞的,所以如果有长时间运行的代码的话事件循环便会被阻塞。为了有效地使用Node.js编写代码,必须仔细思考自己的变成风格并遵循一些简单的规则。
那么,如何将事件添加到你的javascript对象中呢?首先需要通过在对象实例中调用events.EventEmitter.call(this)来在对象中继承EventEmitter功能,还需要把events.EventEmitter.prototype添加到对象的原型中,如:
  1. function myObj(){
  2. Events.EventEmitter.call(this);
  3. }
  4. myObj.prototype._proto_=evnets.EventEmitter.prototype;
然后从对象实例中发出事件:
  1. var newObj=new myObj();
  2. newObj.emit('someEvent');
举个简单的例子:
  1. var events = require('events');
  2. function Account() {
  3. this.balance = 0;
  4. events.EventEmitter.call(this);
  5. this.deposit = function(amount){
  6. this.balance += amount;
  7. this.emit('balanceChanged');
  8. };
  9. this.withdraw = function(amount){
  10. this.balance -= amount;
  11. this.emit('balanceChanged');
  12. };
  13. }
  14. Account.prototype.__proto__ = events.EventEmitter.prototype;
  15. function displayBalance(){
  16. console.log("Account balance: $%d", this.balance);
  17. }
  18. function checkOverdraw(){
  19. if (this.balance < 0){
  20. console.log("Account overdrawn!!!");
  21. }
  22. }
  23. function checkGoal(acc, goal){
  24. if (acc.balance > goal){
  25. console.log("Goal Achieved!!!");
  26. }
  27. }
  28. var account = new Account();
  29. account.on("balanceChanged", displayBalance);
  30. account.on("balanceChanged", checkOverdraw);
  31. account.on("balanceChanged", function(){
  32. checkGoal(this, 1000);
  33. });
  34. account.deposit(220);
  35. account.deposit(320);
  36. account.deposit(600);
  37. account.withdraw(1200);
 

nodejs 事件机制的更多相关文章

  1. nodejs事件机制

    var EventEmitter = function() { this.evts = {}; }; EventEmitter.prototype = { constructor: EventEmit ...

  2. EventEmitter:nodeJs事件触发机制

    Node.js 所有的异步 I/O 操作在完成时都会发送一个事件到事件队列 Node.js 里面的许多对象都会分发事件:一个 net.Server 对象会在每次有新连接时触发一个事件, 一个 fs.r ...

  3. 12.nodejs事件轮询机制

    一:nodejs事件轮询机制  就是  函数的执行顺序 <script type="text/javascript"> setImmediate(function(){ ...

  4. Ext JS学习第十六天 事件机制event(一) DotNet进阶系列(持续更新) 第一节:.Net版基于WebSocket的聊天室样例 第十五节:深入理解async和await的作用及各种适用场景和用法 第十五节:深入理解async和await的作用及各种适用场景和用法 前端自动化准备和详细配置(NVM、NPM/CNPM、NodeJs、NRM、WebPack、Gulp/Grunt、G

    code&monkey   Ext JS学习第十六天 事件机制event(一) 此文用来记录学习笔记: 休息了好几天,从今天开始继续保持更新,鞭策自己学习 今天我们来说一说什么是事件,对于事件 ...

  5. nodeJS中的事件机制

    events模块是node的核心模块,几乎所有常用的node模块都继承了events模块,比如http.fs等.本文将详细介绍nodeJS中的事件机制 EventEmitter 多数 Node.js ...

  6. Node.js入门:事件机制

    Evented I/O for V8 JavaScript     基于V8引擎实现的事件驱动IO.   事件机制的实现     Node.js中大部分的模块,都继承自Event模块(http://n ...

  7. 【iScroll源码学习03】iScroll事件机制与滚动条的实现

    前言 想不到又到周末了,周末的时间要抓紧学习才行,前几天我们学习了iScroll几点基础知识: 1. [iScroll源码学习02]分解iScroll三个核心事件点 2. [iScroll源码学习01 ...

  8. nodejs事件的监听与事件的触发

    nodejs事件(Events) 一.事件机制的实现 Node.js中大部分的模块,都继承自Event模块(http://nodejs.org/docs/latest/api/events.html  ...

  9. nodejs运行机制

    有一天老大忽然问起我这个问题,nodejs运行机制 是怎样的?因自己对nodejs也不是很熟悉,就上网查了一下,得出结果如下: 1.简介 Node.js是一个事件驱动I/O服务端JavaScript环 ...

随机推荐

  1. UVa 11082 - Matrix Decompressing(最大流)

    链接: https://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&page=show_problem& ...

  2. Axure RP 8 学习记录

    一.Axure RP 简介 Axure是一个专业的快速原型设计工具.能够快速创建应用软件或Web网站的线框图.流程图.原型和规格说明文档. 二.Axure RP下载 1.下载安装包 https://w ...

  3. tomcat快速部署War包操作

    Linux快速部署War包操作,暂时是最简单的操作 1.先关闭Tomcat /home/java/tomcat7/bin/shutdown.sh 2.进入War包存放目录(可以通过工具:SSH Sec ...

  4. Filter实现字符集统一设置

    Filter实现字符集统一设置 其实是对request和response请求进行了拦截 1.创建Filter类,实现javax.Servlet接口 doFilter方法 //设置字符集 request ...

  5. mininet的安装

    安装Mininet主要参照李呈的教程 http://www.sdnlab.com/11495.html 我的做法是: 安装虚拟机VM(很容易查找). 需要开启虚拟化: BIOS中依次选择:Advanc ...

  6. IE下内容居中

    ie8下调了很长时间的居中问题,加一个body {text-align:center;},居然解决了.. 参考解决答案:*html * {margin:0px; padding:0;} 然后在盒子里b ...

  7. dnspy的详细配置,dnspy如何过滤反编译之后的乱码,dnspy如何反编译表达式目录树

    dnSpy应该是目前使用最多的.net反编译工具.很多情况下反编译C#代码非常方便,特别是查找基类,子类.搜索一些class,方法.接口,非常方便.比ILspy好很多.而且dnspy是可以配置的. 如 ...

  8. ATM购物作业

    一. 基本需求 模拟实现一个ATM + 购物商城程序 额度 15000或自定义 实现购物商城,买东西加入 购物车,调用信用卡接口结账 可以提现,手续费5% 支持多账户登录 支持账户间转账 记录日常消费 ...

  9. Canvas路径方向

    使用Canvas路径画图需要注意方向,画图方向是顺时针还是逆时针需要记住.下面让我们看看Canvas常见路径方向. arc 参数值 context.arc(x,y,r,sAngle,eAngle,co ...

  10. css中三种隐藏方式

    1.overflow 溢出隐藏 overflow:hidden 2.display 隐藏不占据原来的文档,即会让出空间 display:black  显示 display:none  隐藏 3.vis ...