[Node.js] 04 - Event and Callback

回调函数

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

 

posted @ 2018-04-05 21:26  郝壹贰叁  阅读(333)  评论(0编辑  收藏  举报