treeMany Branches On A Single Tree

All technology is related.  Today, the database has moved to the web, the web has moved to the phone, and the desktop has moved to the cloud.  You need a partner who understands the interconnected nature of today's technologies.

Thank-you-note

Real Stories From Our Customers

Head over to our Case Studies page to read about our projects and hear directly from our customers about their experience with SynaTree.

Read Case Studies

Tracker-and-Share-Rendered-Box

Working With Us Is Easy

SynaTree offers tools that make collaboration on your project effortless.  SynaTree Share makes you a part of the team, while Tracker puts you in control of your project.

Learn More

Aggregator

A Cool Way to Slow Down JavaScript Events

When building a web-2.0 system, it is sometimes neccesary to build code that runs only after a number of dependencies are met. Typically this is done by writing code in a linear fashion, but with XHR/Ajax, you can't be sure which items will load first/second/third.

Aggregator allows a programmer to write the outcome code first, and collect the prerequisites later and in any order. Because it is a closure, it can be passed from code-block to code-block without losing it's payload or original context. In this way, you can literally pass arbitrary code around inside your program, feeding it bits of information it needs one subsystem at a time. As soon as all the requirements are met, the Aggregator runs it's outcome, or destiny function.

/**
	 * The aggregator is an Ajax-friendly simple closure that allows multiple 'stages' to be
	 * defined that must be satisfied before the final function is called.  Stages are input
	 * like this:
	 * {
	 *   'stages': ['a','b','c','d'],
	 *   latch: function(state){ with (state){ return stage1 && stage2 || stage3; }}
	 * }
	 * 
	 * If the latch function is not defined, the default function requires all stages to be
	 * satisfied before releasing the latch.
	 * 
	 * Using the aggregator is simple:
	 * 
	 * var collector = document.Spark.Aggregator({stages: ['a','b','c']}, function(){ alert(arguments.length) } );
	 * 
	 * Once the collector has been set up, ajax methods use collector.curry('a'), while standard
	 * methods use collector.run(['a','data']); or simply collector('a','data');
	 * 
	 * An example:
	 *
	 * var collector = document.Spark.Aggregator({stages: ['a','b','c']}, function(){ alert(arguments.length) } );
	 * Asset.image('image.png', {onload: collector.curry('a')});
	 * collector('b','some important data');
	 * google.maps.GClientGeocoder('1 main street 10076', collector.curry('c') );
	 * 
	 * Once all the stages are satisifed, the function will fire.
	 * 
	 */
	Aggregator:	function(config, finalfn)
	{
		var latch = null; var priv = {}; var state = $H({});
		// first, assign the latching semantics.
		
		// either use the configured latch function or a simple one.
		// the simple latch below examines each member of 'state' to see if it
		// is defined.  If not, it quits. If the latch gets all the way through,
		// it succeeds.
		
		latch = config.latch ? config.latch : ( function(state,priv){
				// release when all values are defined.
				return ! (state.contains(false));
			});
		
		// next, set up the private space for stages and the latch state for each.
		$each(config.stages || config, function(v){
				state[v] = false;
				priv[v] = '';
		});
		
		// next, define the closure.
		
		var r = function(stage, data){
			if (stage && !state[stage]) {
				priv[stage] = data;
				state[stage] = true;
			}
			if(latch(state,priv))
				return finalfn(priv);
		}
		
		return r;
		
	}
blog comments powered by Disqus