登录
注册
node.js 学习社区
对EventProxy模块代码的研究和心得。。。

卷卷儿

2014-12-01 09:36

 如果大家研究过node_club源码,想必不会对EventProxy模块感到陌生吧!该模块是由@朴灵所创作出来的,该模块有如下几大特点:
  • 利用事件机制解耦复杂业务逻辑
  • 移除被广为诟病的深度callback嵌套问题
  • 将串行等待变成并行等待,提升多异步场景下的执行效率
  • 无平台依赖,适合前后端,能用于浏览器和Node.js

想要获取eventproxy源码的童鞋们可以通过命令npm install eventproxy或者直接去github网站获取,网址为:[enter link description here][1]

[1]: https://github.com/JacksonTian/eventproxy 那里面有较为详细的介绍,好了,接下来我们步入正题,进行对eventproxy模块源码的探究之旅吧!

由于eventproxy模块中的其他方法都相对来说比较简单,这里,我就不再多费笔墨来解读呢,主要针对其中的_assign方法进行分析,它也是eventproxy的核心所在吧!

var _assign = function (eventname1, eventname2, cb, once){...}

很多内置的函数都使用到了该函数,比如:EventProxy.prototype.all和EventProxy.prototype.tail等方法。好了,接下来我们将其源码剪切下来,其中有对关键代码的详细注释,相信大家一看就很清楚呢!

 var _assign = function (eventname1, eventname2, cb, once) {
    var proxy = this, length, index = 0, argsLength = arguments.length,
        bind, _all,
        callback, events, isOnce, times = 0, flag = {};

    // Check the arguments length.
    if (argsLength < 3) {
        //由于参数列表的最后两项分别是回调函数
        //和是否只进行一次监听的标识位,因此加上要监听一事件,
        //所以参数列表的长度至少是3位或者3位以上,否则直接返回。
        return this;
    }

    //获取所有要进行监听的事件名
    events = Array.prototype.slice.apply(arguments, [0, argsLength - 2]);
    //获取回调函数
    callback = arguments[argsLength - 2];
    //获取监听标识位
    isOnce = arguments[argsLength - 1];

    // Check the callback type.
    if (typeof callback !== "function") {
        return this;
    }

    length = events.length;
    //bind函数是关键,主要用于各个需要监听的事件绑定到一个指定函数里,主要通过
    //method指定的方法进行事件的绑定(once或者bind函数),同时在function(data){...}
    //函数里对将传递过来的参数记录下来,以便之后传递给回调函数,并且在这个函数里地相应事件的触发
    //进行计数,以便在所有监听的事件都触发后,对callback函数进行回调,见下文
    bind = function (key) {
        var method = isOnce ? "once" : "bind";
        //proxy[method]事实就是指eventproxy模块上下文的bind和once事件,进行相应的绑定操作
        proxy[method](key, function (data) {
            proxy._fired[key] = proxy._fired[key] || {};
            //对相应事件传递过来的实参进行记录
            proxy._fired[key].data = data;
            if (!flag[key]) {
                flag[key] = true;
                //times用于对触发相应事件时完成对其的计数功能
                times++;
            }
        });
    };

    for (index = 0; index < length; index++) {
        //依次对监听的事件进行绑定,使用上面的bind函数(注意不是上下文的bind函数)
        bind(events[index]);
    }

    _all = function () {
        if (times < length) {
            //这里是重点,作用是为了判断是否所有的监听事件都已经完成了触发动作(可以通过emit事件)
            //,如果还有未触发的事件,则跳出当前函数,也就放弃了对回调函数的调用过程,理解这点对
            //assign函数的原理也就差不多理清楚了
            return;
        }
        var data = [];
        for (index = 0; index < length; index++) {
            //获取所有监听事件所传递过来的实参,以便给回调函数使用
            data.push(proxy._fired[events[index]].data);
        }
        if (isOnce) {
            //当isOnce为true时,则将all事件进行去除绑定,那么回调函数也只会在
            //所有监听事件触发完成后被调用一次,此后便不会再进行回调。
            //相反,如果当isOnce为false时,则在所有监听事件触发完成之后的时间里,
            //只要触发任意的监听函数都会对回调函数进行回调调用。这也就assign和assignAll的本质差异!!!
            proxy.unbind("all", _all);
        }
        //对回调函数进行回调(需要理解javascript的apply或者cal方法的使用)
        callback.apply(null, data);
    };
    //对_all事件进行绑定,以便能够正确对回调函数进行回调
    proxy.bind("all", _all);
};

以上便是对_assign方法的详细说明,注释已经写得比较清楚呢。如果对上述方法的原理理解透彻呢,想必会对看懂node_club源码有所帮助的。顺便提醒一个,上述函数中涉及到了javascript的函数闭包的内容,比如为什么_assign函数中的局部变量times能够一起存活下去?这里大家就需要对函数闭包的知识有所了解才能弄懂了,在这里只是顺带提一下,应该说闭包的内容还是比较复杂的,三言两语也说不清,不懂的就直接去找相关资料进行学习吧。如果有机会,自己也会把自己对对闭包的理解写出来,供大家评阅!!!上述有什么表述不清或者不准确的地方欢迎大家的随时拍砖!!!共同学习!!!

原文引自:http://cnodejs.org/topic/4f76cafe8a04d82a3d556a07

回复 · 0

发表回复

你可以在回复中 @ 其他人