2
\$\begingroup\$

I'm working on a singleton object to manage size changes in the viewport, I wanted it to be a singleton because there may be different unrelated objects that need to be notified when a change in viewport dimensions has occurred. So I came up with this solution based on the singleton design pattern found in here.

var CAResizeManager = ( function () {

    var instance;

    function init() {

        var o_actions   = [];
        var o_cache_pos = {};
        var o_timeout;

        /* 
         * Custom 'addEvent' function;
         */
        addEvent( window, 'resize', function () {

            /* 
             * Clear timeout if resize is called severla times in short timespan.
             */
            clearTimeout( o_timeout );

            o_timeout = setTimeout( function () {

                var o_viewport_size = getViewportSize();
                /* 
                 * Loop through the actions array to pass new viewport size;
                 */
                for ( var i = o_actions.length - 1; i >= 0; i-- ) {
                    var o_func = o_actions[ i ];

                    if ( o_func ) {
                        o_func( o_viewport_size );
                    }
                }

            } ,300 );


        } );

        return {
            addAction: function ( arg_func ) {

                /*
                 * Generates a unique id to identify action.
                 */
                var i_id = Math.random().toString().replace( '0.', '' );

                o_actions.push( arg_func );

                /* 
                 * Store position in an object to avoid looping through the 
                 * actions array.
                 */ 
                o_cache_pos[ i_id ] = o_actions.length === 0 ? 0 : o_actions.length - 1;                

                /*
                 * Return id to external object.
                 */
                return i_id;
            },
            removeAction: function ( arg_id ) {

                var i_index = o_cache_pos[ arg_id ]; 

                /* 
                 * Check if id exists;
                 */
                if ( i_index ) {
                    return;
                }

                /* 
                 * Remove action from array
                 */
                o_actions.splice( i_index, 1 );

                /* 
                 * Delete positon from cache;
                 */
                delete o_cache_pos[ arg_id ];

            }
        };
    }

    return {
        getInstance: function () {

            if ( !instance ) {
                instance = init();
            }

            return instance;

        }
    }

} )();
\$\endgroup\$

1 Answer 1

3
\$\begingroup\$

Here's a simplified version of your code:

var ResizeManager = (function(addEvent, getViewportSize){

  var DEBOUNCE_DELAY = 300;
  var debounceTimer = null;
  var trackedEvents = {};

  addEvent(window, 'resize', function() {
    if(debounceTimer) clearTimeout(debounceTimer);
    debounceTimer = setTimeout(function(){
      Object.keys(trackedEvents).forEach(function(handler){
        handler.call(null, getViewportSize());
      });
    }, DEBOUNCE_DELAY);
  });

  return {
    addAction : function(callback){
      var actionId = ('' + Math.random()).slice(2);
      trackedEvents[actionId] = callback;
      return actionId;
    },
    removeAction: function(callbackId){
      delete trackedEvents[callbackId];
    }
  };

}(addEvent, getViewportSize));

Here's the changes:

  • Dropped getInstance. Since it's a singleton, let's treat the ResizeManager as the instance, instead of still doing a getInstance step.

  • Using an object (hash) instead of an array to collect your handlers. The advantage is that you can immediately delete the action by ID instead of having to search for it befor delete.

  • Replaced your ID generator with a much sleeker alternative.

  • Naming variables properly, as well as using the constant convention (all caps, underscore-spaced) for constant values.

  • Calling your function with the context of null. That way, your handlers won't expect a context and potentially do something weird.

  • Localizing references to the global functions. That way, if ever they get re-assigned a value, you still hold a reference to them.

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.