node源码实现——EVENT

EVENT(事件)的作用

在node中很多异步方法需要监听事件,比如数据传输时需要监听流是否传输成功(data事件),数据是否传输完毕(end事件)。所以需要一个模块用来存储事件相关的操作(事件注册、事件监听、事件触发).

EVENT的机制

  1. 对于需要事件相关操作的函数,只需将其构造函数的原型指向事件的构造函数。这样其实例就能取得事件操作的方法。
  2. 对于事件库本身,提供事件的注册、监听、触发、取消绑定以及事件方法池。

    EVENT实现原理

  3. 设定一个事件方法池。
  4. 当监听事件时,将事件名与其对应回调函数放入方法池。
  5. 触发事件时,从方法池中找到相应事件名,依次执行事件名下保存的回调函数。

    代码实现

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    //事件构造函数
    function Event () {
    //事件方法池
    this._events={};
    }
    //事件的监听
    Event.prototype.on=function (eventName,callback) {
    var listeners=this._events[eventName];
    //如果事件方法池中存在对应方法名
    if (listeners) {
    //在对应方法名数组中新加入一个回调函数
    listeners.push(callback);
    } else {
    //事件方法池中对应方法名赋值为一个含回调函数的数组
    this._events[eventName]=[callback];
    }
    }
    //事件的触发
    Event.prototype.emit=function (eventName) {
    //第一项传参(也是形参)是事件名,从第二项开始就是传递给回调函数的参数,这里将这些参数保存在数组里
    var args=Array.prototype.slice.call(arguments,1);
    var listeners=this._events[eventName];
    //如果事件方法池中存在相应的方法名
    if (listeners) {
    for (var i=0;i<listeners.length;i++) {
    //依次执行方法名所对应的回调函数
    listeners[i].apply(null,args);
    }
    } else {
    console.log('对应方法不存在')
    }
    }
    //事件的移除
    Event.prototype.removeListener=function (eventName,callback) {
    this._events[eventName].filter(function (fn){
    return fn!=callback;
    })
    }
    //只执行一次的事件
    Event.prototype.once=function (eventName,callback) {
    //原理是执行完回调函数后移除这个事件
    //存储this指向,用以在one函数中调用指向once函数
    var that=this;
    function one () {
    //存储可能的传参
    var args=Array.prototype.slice.call(arguments);
    //执行回调函数
    callback.apply(that,args);
    //执行完后移除事件,这里的this指向的是事件实例
    this.removeListener(eventName,one);
    }
    //监听名为one的函数
    this.on(eventName,one);
    }
    module.exports=Event;

使用方法

1
2
3
4
5
6
7
8
9
10
11
12
//引入继承模块
var util=require('util');
//A构造函数的实例继承事件库方法
function A () {
//A的实例取得Event的实例属性
Event.apply(this);
}
//A.prototype的原型指向Event.prototype
util.inherits(A,Event);
//这样A的实例就继承了事件库的方法