[Node.js] 04 - Event and Callback

时间:2020-12-16 06:40:35

回调函数

回调函数在完成任务后就会被调用,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。

[Node.js] 04 - Event and Callback

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

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

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

[Node.js] 04 - Event and Callback