回调函数

回调函数在完成任务后就会被调用,Node 使用了大量的回调函数,Node 所有 API 都支持回调函数。

异步读取文件的回调函数:

var fs = require("fs");

fs.readFile('input.txt', function (err, data) {
if (err) return console.error(err);
console.log(data.toString());
}); console.log("程序执行结束!");

观察者监视事件

Node.js 的每一个 API 都是异步的

Node.js 基本上所有的事件机制都是用设计模式中观察者模式实现。

Node.js 单线程类似 进入一个while(true)的事件循环,直到没有事件 观察者退出,每个异步事件都生成一个事件观察者,如果有事件发生(观察者)就调用该回调函数。

有点类似于观察者模式,事件相当于一个主题(Subject),而所有注册到这个事件上的处理函数相当于观察者(Observer)。

var events       = require('events');
var eventEmitter = new events.EventEmitter();
--------------------------------------------------------------------
// 方法1.采用handler函数
// 创建事件处理程序
var connectHandler = function connected() {
console.log('连接成功');            // step 1
eventEmitter.emit('data_received');     // 这里触发 step 2
} // 绑定 connection 事件处理程序
eventEmitter.on('connection', connectHandler);

-------------------------------------------------------------------- // 方法2.采用匿名函数(或者箭头函数)
// 使用匿名函数绑定 data_received 事件
eventEmitter.on('data_received', function(){
console.log('数据接收成功');          // step 2
}); // 触发 connection 事件
eventEmitter.emit('connection');        // 这里触发 step 1 console.log("程序执行完毕。");       // step 3

多个观察者

//event.js 文件
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', 'arg1 参数', 'arg2 参数');

当事件触发时,注册到这个事件的事件监听器被依次调用,事件参数作为回调函数参数传递。

$ node event.js
listener1 arg1 参数 arg2 参数
listener2 arg1 参数 arg2 参数

延时触发

//event.js 文件
var EventEmitter = require('events').EventEmitter;
var event = new EventEmitter();
event.on('some_event', function() {
console.log('some_event 事件触发');
});
setTimeout(function() {
event.emit('some_event');
}, 1000);

顺便提一个:间隔触发

setInterval ( ); --> clearInterval(timer);

<script type="text/javascript">
window.onload = function () {
var count = 0;
var bt = document.getElementById("bt");
function show(){
document.getElementById("ant").innerHTML = count + 1;
count = count +1;
}
var flag = setInterval(show, 1000);
bt.onclick = function () {
clearInterval(flag);
}
}
</script>

一个综合性的例子:

var events       = require('events');
var eventEmitter = new events.EventEmitter();

// (1) 定义监听回调方法
// 监听器 #1
var listener1 = function listener1() {
console.log('监听器 listener1 执行。');
} // 监听器 #2
var listener2 = function listener2() {
console.log('监听器 listener2 执行。');
}

// (2) 两种绑定监听器到事件上
// 绑定 connection 事件,处理函数为 listener1
eventEmitter.addListener('connection', listener1); // 绑定 connection 事件,处理函数为 listener2
eventEmitter.on('connection', listener2);

var eventListeners = require('events').EventEmitter.listenerCount(eventEmitter,'connection');
console.log(eventListeners + " 个监听器监听连接事件。");

// (3) 触发事件发生
// 处理 connection 事件
eventEmitter.emit('connection');

// (4) 去掉监听器
// 移除监绑定的 listener1 函数
eventEmitter.removeListener('connection', listener1);
console.log("listener1 不再受监听。"); // 触发连接事件
eventEmitter.emit('connection'); eventListeners = require('events').EventEmitter.listenerCount(eventEmitter,'connection');
console.log(eventListeners + " 个监听器监听连接事件。"); console.log("程序执行完毕。");

Error 事件

EventEmitter 定义了一个特殊的事件 error,它包含了错误的语义,遇到 异常的时候通常会触发 error 事件。

当 error 被触发时,EventEmitter 规定如果没有响 应的监听器,Node.js 会把它当作异常,退出程序并输出错误信息。

我们一般要为会触发 error 事件的对象设置监听器,避免遇到错误后整个程序崩溃。例如:

var events = require('events');
var emitter = new events.EventEmitter();
emitter.emit('error');

继承 EventEmitter

大多数时候我们不会直接使用 EventEmitter,而是在对象中继承它。包括 fs、net、 http 在内的,只要是支持事件响应的核心模块都是 EventEmitter 的子类。

为什么要这样做呢?原因有两点:

  • 首先,具有某个实体功能的对象实现事件符合语义, 事件的监听和发生应该是一个对象的方法。
  • 其次 JavaScript 的对象机制是基于原型的,支持 部分多重继承,继承 EventEmitter 不会打乱对象原有的继承关系。

Person类本身会有多个有意义的对象,比如:xiaoming, lili, lucy。

希望他们对同一个事件都会有类似的反应,比如老师喊报名,各自起来报自己姓名。

故,这里触发事件speak绑定在每一个person身上。

之后,触发了xiaoming的神经;触发了lucy的神经。

[Node.js] 04 - Event and Callback的更多相关文章

  1. 浅析Node.js的Event Loop

    目录 浅析Node.js的Event Loop 引出问题 Node.js的基本架构 Libuv Event Loop Event Loop Phases Overview Poll Phase The ...

  2. 定时器setTimeout()和Node.js的Event Loop

    一.定时器 setTimeout(fn,0)的含义是,指定某个任务在主线程最早可得的空闲时间执行,也就是说,尽可能早得执行.它在"任务队列"的尾部添加一个事件,因此要等到同步任务和 ...

  3. Node.js的process.nextTick(callback)理解

    Node.js是单线程的,基于事件循环,非阻塞 IO的.事件循环中使用一个事件队列,在每个时间点上,系统只会处理一个事件,即使电脑有多个CPU核心,也无法同时并行的处理多个事件.因此,node.js适 ...

  4. 理解 Node.js 的 Event loop

    问题 考察如下代码,脑回路中运行并输出结果: console.log("1"); setTimeout(function setTimeout1() { console.log(& ...

  5. Node.js学习 - Event Loop

    Node.js本身是单线程,但通过事件和回调支持并发,所以性能非常高. Node.js的每一个API都是异步的,并作为一个独立线程运行,使用异步函数调用,并处理并发. 事件驱动程序 实例 var ev ...

  6. 【Node.js】Event Loop执行顺序详解

    本文基于node 0.10.22版本 关于EventLoop是什么,请看阮老师写的什么是EventLoop 本文讲述的是EventLoop中的执行顺序(着重讲setImmediate, setTime ...

  7. node.js 中回调函数callback(转载),说的很清楚,看一遍就理解了

    最近在看 express,满眼看去,到处是以函数作为参数的回调函数的使用.如果这个概念理解不了,nodejs.express 的代码就会看得一塌糊涂.比如: 复制代码 代码如下: app.use(fu ...

  8. [转]使用Node.js完成的第一个项目的实践总结

    本文转自:http://blog.csdn.net/yanghua_kobe/article/details/17199417 https://github.com/yanghua/FixedAsse ...

  9. Node.js 打造实时多人游戏框架

    在 Node.js 如火如荼发展的今天,我们已经可以用它来做各种各样的事情.前段时间UP主参加了极客松活动,在这次活动中我们意在做出一款让“低头族”能够更多交流的游戏,核心功能便是 Lan Party ...

随机推荐

  1. Linux学习笔记13—Vi编辑器的学习

    文本编辑工具vim.vi1. vim与vi的最大区别是vim编辑的时候是带颜色显示的.Vi不带颜色显示.2. yum install -y vim-enhanced 如果没有安装VIM 使用上面的命令 ...

  2. Android笔记(四):RecyclerView

    RecyclerView是ListView的增强版.有了它之后,你就可以抛弃ListView了. recycle,重复利用.在ListView里,我们得自己写重复利用View的代码,而Recycler ...

  3. Android笔记(五):广播接收者(Broadcast Receiver)

    Android有四大组件,分别为:Activity(活动).Service(服务).Content Provider(内容提供器).Broadcast Receiver(广播接收者). 引入广播的目的 ...

  4. 枚举进程句柄File,Section,Mutant,Timer关闭Mutex句柄实现游戏多开

    原文:http://www.cnblogs.com/Y4ng/archive/2012/09/06/EnumProcessHandle_EnumMutex.html 相信做过游戏多开的朋友就会发现,很 ...

  5. Scala:Object-Oriented Meets Functional

    Have the best of both worlds. Construct elegant class hierarchies for maximum code reuse and extensi ...

  6. 使用别名访问MSSQL Express

    当MSSQL Express安装成功后,默认只能用 .\sqlexpress 或者 (local)\sqlexpress 有时候我们希望使用(local) 就可以访问,此时就可以利用别名 1.MSSQ ...

  7. libnids使用 (转)

    http://blog.csdn.net/kl222/article/details/6248827---原始链接 Libnids是一个用于网络入侵检测开发的专业编程接口,它使用了Libpcap所以它 ...

  8. PL/SQL学习笔记之存储过程

    一:PL/SQL的两种子程序 子程序:子程序是执行一个特定功能.任务的程序模块.PL/SQL中有两种子程序:函数  和  过程. 函数:主要用于计算并返回一个值. 过程:没有直接返回值,主要用于执行操 ...

  9. 使用js获取QueryString的方法小结

    一.<script> urlinfo=window.location.href; //获取当前页面的url len=urlinfo.length;//获取url的长度 offset=url ...

  10. linux使用pam_tally2.so模块限制登录3次失败后禁止5分钟

    在线上的服务器有时需要限制用户登录次数.这个功能可以通过pam的pam_tally2.so模块来实现 PAM模块是用sun提出的一种认证机制 pam_tally2.so模块 一.格式 pam_tall ...