PubSub的一种实现

今天在浏览JavaScript事件时,复习了下Dean Edward大神的addEvent。突然觉得可以基于他的思路实现一个结构更好的PubSub。

思路也很简单,就是要维护一个类似如下的一个仓库结构:

/*
{
    'sayHello': {
        0: fn0,
            1: fn1,
        //...

    },
    'sayGoodBye': {
        0: fnn,
        //...
    },
    //...
}*/

下面是我的实现代码:

(function(exports) {
    var PubSub = exports.PubSub || {};

    //在PubSub对象上增加静态域PubSubCache,用于保存subscribe相关数据

    /**
     * PubSub.PubSubCache仓库结构
     * {
     *     'sayHello': {
     *         0: fn0,
     *         1:fn1,
     *         //..。
     *     },
     *     'sayGoodBye': {
     *        //...
     *     }
     * }
     *
     */
    PubSub.PubSubCache = PubSub.PubSubCache || {$uid: 0};

    //PubSub有4个静态方法:subscribe, subscribeOne, unsubscribe, publish
    //PubSub不会与DOM元素有关系。这样publish也只能手动去触发了
    PubSub.subscribe = function(type, handler) {
        var cache = this.PubSubCache[type] || (this.PubSubCache[type] = {});
        handler.$uid = handler.$uid || this.PubSubCache.$uid++;

        //把回调放入仓库中
        cache[handler.$uid] = handler;
    };

    PubSub.unsubscribe = function(type, handler) {
        var counter = 0,$type, cache = this.PubSubCache[type];

        if(arguments.length === 1) {
            //直接删除此种类型的订阅对象
            if(!cache) return true;
            return !!this.PubSubCache[type] && (delete this.PubSubCache[type]);
        } else if(arguments.length === 2) {
            !!this.PubSubCache[type] && (delete this.PubSubCache[type][handler.$uid]);
        }

        //PubSubCahe仓库中某类型订阅为空,则要删除这个订阅对象
        for($type in cache) {
            counter++;
        }

        return !counter && (delete this.PubSubCache[type]);
    };

    PubSub.publish = function(type) {
        var cache = this.PubSubCache[type], key, oneFlag, tmp, context, args = [].slice.call(arguments);

        if(!cache) return;

        if(args.length === 1) {
            context = exports;
        } else {
            context = args[1];
        }

        //执行回调
        for(key in cache) {
            tmp = cache[key];
            //在发布消息时可以指定回调函数的上下文,同时还可以传入参数
            cache[key].apply(context, args.slice(1));
            tmp.one && this.unsubscribe(type, tmp);
        }
    };

    PubSub.subscribeOne = function(type, handler) {
        this.subscribe(type, handler);
        //给函数加一个只执行一次的标志
        handler.one = true;
    };

    exports.PubSub = PubSub;
})(window);
 

下面是测试代码:

var data = {name: 'haha', age:18};

var handler2 = function(data) {
    console.log('say.hello excuted! 2');
    console.log(this.name);
};

//订阅say.hello消息
PubSub.subscribe('say.hello', function(data) {
    console.log('say.hello excuted! 1');
});

//第二次订阅say.hello消息
PubSub.subscribe('say.hello', handler2);

//第三次订阅say.hello消息
PubSub.subscribe('say.hello', function(data) {
    console.log('say.hello excuted! 3');
    console.log(this.age);
});

//第四次增加一个只会执行一次的say.hello消息订阅
PubSub.subscribeOne('say.hello', function(data) {
    console.log('say.hello excuted! one');
});

/**
 * 发布say.hello消息类型
 * 输出:
 * say.hello excuted! 1
 * say.hello excuted! 2
 * haha
 * say.hello excuted! 3
 * 18
 * say.hello excuted! one
 */


PubSub.publish('say.hello', data);


//取消第二次订阅的say.hello类型
PubSub.unsubscribe('say.hello', handler2);


/**
 * 发布say.hello消息类型
 * 输出:
 * say.hello excuted! 1
 * say.hello excuted! 3
 * 18
 */

console.log('--------------------------------')
PubSub.publish('say.hello', data);

/**
 * 再次发布say.hello消息,不过这次除了传入执行上下文外,还要传入参数
 * 输出:
 * say.hello excuted! 1
 * say.hello excuted! 3
 * 18
 * say.hello excuted! has deliverd args
 * args123
 */

PubSub.subscribe('say.hello', function(data, args) {
    console.log('say.hello excuted! has deliverd args');
    console.log(args);
});

console.log('--------------------------------')
PubSub.publish('say.hello', data, 'args123');

小结:

全局的PubSub对象有四个方法:

1. subscribe(type, handler) :增加一种类型的消息订阅。类似jQuery的bind();

2. subscribeOne(type, handler):增加一种回调只会执行一次的消息订阅,类似jQuery的one()

3. unsubscribe(type, [handler]): 如果只传type,会删除所有的type消息订阅;传入了回调函数,则只删除那一个回调。类似jQuery的unbind()

4. publish(type):执行订阅。类似jQuery的trigger();

 

当然上面的功能Cowboy大神只用了只行代码就实现了(基于jQuery):

(function($) {
    //得到一个jQuery对象,以便使用其方法
    var o = $({});    
    
    //为jQuery对象增加静态的方法
    $.subscribe = function() {
        o.bind.apply(o, arguments);
    };
    
    $.unsubscribe = function() {
        o.unbind.apply(o, arguments);
    };
    
    $.publish = function() {
        o.trigger.apply(o, arguments);
    }
    
})(jQuery);

转载于:https://www.cnblogs.com/jagusOu/p/3855388.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值