订阅服务器在实例化库时无法侦听启动事件

时间:2014-04-18 01:11:24

标签: javascript design-patterns refactoring publish-subscribe

我希望允许用户在我的代码生命周期中订阅事件,因此我已经包含了一个pubsub机制,一旦实例化了库,该机制就可供用户使用。它在大多数情况下运作良好。代码看起来像这样:

var library = function() {

    //library code here

    //Publish some sort of initialisation event
    ev.publish('init');

    //return an object that includes the ev pubsub functionality 

};

然后我想象一个用户可能能够像这样进行交互:

var test = new library();
//the ev object is returned from the instantiation of the library
test.ev.subscribe('init',function() {});

这大部分都有效 - 订阅功能可以挂钩到所有帖子初始化发布。

问题在于实例化库并触发各种初始化事件。用户无法与初始化期间触发的发布事件进行交互,因为当用户有机会订阅任何已启动的启动事件时。

如何重构此代码以允许完整捕获事件系统?

2 个答案:

答案 0 :(得分:1)

有几种方法可以实现这种目的。根据您的架构,要求和偏好,您可以执行以下任一操作:

方法1:
你可以接受一个回调函数作为init函数,你可以在那里处理它。

var library = function(initCallback) {
     ev.subscribe('init', initCallback);
    //library code here

    //Publish some sort of initialisation event
    ev.publish('init');

    //return an object that includes the ev pubsub functionality 
};

然后你可以像

一样打电话
var test = new library(function() {});

方法2:
将init函数与实例化分开。这种架构最常用。您只能将所选方法公开为公开。

var library = function() {

    //library code here

    //Publish some sort of initialisation event
    function init() {
        ev.publish('init');
    }

    //return an object that includes the ev pubsub functionality 
    return {
       init : init,
       ev : ev,
       // .... expose other function/properties
    };

};

然后您可以使用它:

var test = new library();
//the ev object is returned from the instantiation of the library
test.ev.subscribe('init',function() {});
//Call the actual initialization
test.init();

方法3:
正如您所说,您不希望遵循上述两种方法,那么通过从对象移动事件处理程序,可能只有一种方法可以实现您想要的效果。由于您还未提供事件处理程序代码,因此我将使用jquery事件处理程序提供示例实现。

var library = function() {

    //library code here

    //Publish some sort of initialisation event
    var self = this;
    $(window).trigger( "init.library", [ self ] );

    //return an object that includes the ev pubsub functionality 

};
你可以这样使用:

$(window).on( "init.library", function( event, obj ) {

//Do whatever you want with "obj"

});

var test = new library();

如果你不想使用最后一种方法,那么祝你好运:)。如果您发现任何其他有趣的解决方案,请将其发布给其他人。实际上你可以做的另一件事,如果你的目的只是调用init函数,实例化对象(而不是实例化),那么你可以将ev.publish('init');行更改为

setTimeout(function() {
    ev.publish('init');
 },1);

然后你的代码也会工作!!

快乐的编码!!

答案 1 :(得分:0)

我选择了一种使用队列数组的方法。如果发布者被解雇且没有相应的订阅者,则将发布添加到挂起的数组中。然后,任何新添加的订阅者都会检查挂起的数组,如果有匹配的发布条目,则触发订阅者回调。

http://jsfiddle.net/uMCFT/3/

var uid, topics, pending = {};

uid = 0;

topics = {};


subscribe = function (topic, fn) {

    if (!topics.hasOwnProperty(topic)) {

        topics[topic] = {};

    }

    topics[topic][++uid] = fn;

    for(var key in pending) {

        if(pending[key] === topic) { 

            delete pending[key]; 

            for (key in topics[topic]) {

                topics[topic][key](topic);

            }

        }

    }

};



publish = function (topic, obj) {
    var key;

    if(!topics.topic) {
       pending[topic] = topic;
    }

    if (topics.hasOwnProperty(topic)) {
        for (key in topics[topic]) {
            topics[topic][key](topic, obj);
        }
    }
};


publish('that');

subscribe('that',function() {console.log('hi')});