对 jQuery tiny PubSub 的改进

最近在做一个项目的时候, 需要用到同事写的一个js 模块, 为了让我写的新模块与之通信, 我一开始用的是旧模块里的一个全局变量. 但是由于历史原因, 这个全局变量不知道啥时候就会被旧模块所修改, 因此遇到了不少Bug. 最后我放弃了共享全局变量的做法, 改用PubSub. 使用PubSub 的好处是减少了对全局变量的依赖, 降低了模块之间的耦合程度, 从而减少了模块高耦合带来的风险.

我之前使用的PubSub 是 jQuery Tiny Pub/Sub, 这几行代码利用了jQuery 的事件api, 实现了相当简练PubSub, 但我遇到了一个缺陷: 在传递数组时有Bug.

$.publish('test',1);       //1
$.publish('test',{a:1});   //{a:1}
$.publish('test',[2,3,4]); //2, it should be [2,3,4] instead
$.publish('test',{arr:[2,3,4]})  //{arr:[2,3,4]}

这个问题让我很头疼, 又无法绕开, 因为这是jQuery 事件api 的写法所致. 随后我决定自己写一个PubSub.

(function(Global){
    var cache = {};
    Global.PubSub = Global.PubSub||{
        on: function(e,fn){
            if(!cache[e]){
                cache[e]=[];
            }
            cache[e].push(fn);
            return fn;
        },
        off: function(e,fn){
            if(!cache[e]){
                return;
            }
            var fns = cache[e];
            if(!fn){
                fns.length=0;
            }
            for(var i=0;i<fns .length;++i){
                if(fns[i]===fn){
                    fns.splice(i,1);
                }
            }
        },
        trigger: function(e,data){
            if(!cache[e]){
                return;
            }
            var fns = cache[e];
            for(var i=0;i<fns.length;++i){
                fns[i](e,data);
            }
        }
    };
})(typeof window!=='undefined'?window:this);

PubSub.on('test', function (e, data) {
    console.log(data);
});
PubSub.trigger('test', 1);
PubSub.trigger('test', {
    a: 1
}); //{a:1}
PubSub.trigger('test', [2, 3, 4]); //[2,3,4]
PubSub.trigger('test', {
    arr: [2, 3, 4]
}); //{arr:[2,3,4]}

需要注意的是, 这个改进的 PubSub 有几个问题:
1. 在调用各事件的listener 时没有使用异步, 因为我觉得没什么必要;
2. 在使用这个PubSub 时应当避免listener 修改引用类型的参数, 因为这会影响到其他listener, 如下例子中, 由于listenerHarmful 修改了传入的参数[2,3,4], 导致listenerInnocent 接收到的参数是 [] . 对此我没有做过多限制, 因为我相信PubSub 使用者对观察者模式的理解.

function listenerHarmful(event, data){
    data.length=0;
}
function listenerInnocent(event, data){
    console.log(data);
}
PubSub.on('test', listenerHarmful);
PubSub.on('test', listenerInnocent);
PubSub.trigger('test',[1,2,3]); 

3. 如果需要异步等高级特性, 请使用其他人实现的PubSub.

参考资料:
Learning JavaScript Design Patterns – The Observer Pattern

本站文章除注明转载外,均为本站原创编译
转载请注明以下信息
文章转载自:鲁夫的爱 [ https://opengg.me/ ]
本文标题:对 jQuery tiny PubSub 的改进
本文地址:https://opengg.me/853/jquery-tiny-pubsub-improve/

发表评论

电子邮件地址不会被公开。 必填项已用*标注