Pregunta

I want to allow users to subscribe to events in my codes lifecycle so i've included a pubsub mechanism which is made available to the user as soon as the library has been instantiated. It works well for the most part. The code looks like something this:

var library = function() {

    //library code here

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

    //return an object that includes the ev pubsub functionality 

};

then I imagined a user might be able to interact with it like so:

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

This works for the most part - the subscribe function can hook in to all post initialisation publishes.

The Problem lies with when the library is instantiated and various initialisation events are fired. There's no way for a user can interact with the publish events that are fired during initialisation because by the time the user is given an opportunity to subscribe to anything those startup events have already been fired.

How can I refactor this code to allow the event system to be captured in full?

¿Fue útil?

Solución

There are several approach to achieve this kind of thing. Based on your architecture, requirements, preference you can do either of the following:

Approach 1 :
You can accept a callback function as a init function and there you can handle it.

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 
};

Then you can call like

var test = new library(function() {});

Approach 2 :
Separate the init function from instantiate. This architecture used most. You can expose selected method only as public.

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
    };

};

Then you can use this like:

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();

Approach 3:
As you stated you do not want to follow neither of above approaches, then there may be only one way to achieve what you want, by moving the event handler from your object. As you haven't gave your event handler code, I am giving an example implementation with jquery event handler.

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 

};

hen you can use this like:

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

//Do whatever you want with "obj"

});

var test = new library();

If you do not want to use the last approach, then best of luck :). And if you find any other interesting solution, please post it for others. Actually another thing you can do, if your purpose is to just call the init function, after instantiate of the object(not while instantiating) then you can change ev.publish('init'); line as

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

Then your code will also work!!

Happy coding!!

Otros consejos

I settled on an approach that used a queue array. If a publisher is fired and there are no corresponding subscribers then the publish is added to a pending array. Then any newly added subscribers check the pending array and if there's a matching publish entry then fire the subscribers callback.

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')});
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top