Deferment Pattern

Sometimes a function you want to execute may have some internal variable that has yet to be loaded. The Deferment Pattern requires that you add a little extra code to the function, but allows you to call it at any time, forcing the function to wait until the internal variables are ready. For Mint.com I have developed an on-demand Dialog system that uses AJAX to retrieve the Dialog DOMs as needed. However, I often need to access the object immediately after instantiation, which is long before the server has returned the DOM. For situations like this, I find that, lately I have been leveraging the Deferment Pattern.

For example, suppose you have an alert Dialog that you want to retrieve from the server:

Example 1: Calling Dialog Manager

var dialog = Core.Widget.DialogManager.get(alert);

Assume that DialogManager is somewhere in your library and it initiates an AJAX request to retrieve the Dialog DOM, then returns a Dialog object. Somewhere in DialogManager this Dialog object will be cached and the DOM loaded appropriately when the AJAX request is returned. But in the the meantime you have the dialog variable and you want to start manipulating it right away. Say, the Dialog object has a method show, which makes the Dialog visible, and you want to call that function immediately:

Example 2: Showing the Dialog

var dialog = Core.Widget.DialogManager.get(alert);
dialog.show();

Without the Deferment Pattern this would most likely crash (or do nothing), because the Dialog DOM is empty, as the AJAX request most likely has not returned yet. Lets assume that when the AJAX request returns, the Object dom is attached to the Dialog object and that this object contains a reference to the HTML element for the Dialog DOM associated to the body key (dom = {body: element}). Therefore, the show method might be as simple as:

Example 3: Basic Show

dialog.show = function() {
	this.dom.body.style.display = block;
};

Obviously, this function would fall into the pitfall mentioned above. Therefore, we add the Deferment Pattern, to force the function to wait until dom.body is ready.

Example 4: Show Using Deferment Pattern

dialog.show = function() {
	var that = this;

	// deferment block; if the node doesnt exist yet, wait for it
	if (! (this.dom && this.dom.body)) {
		setTimeout(function() {that.show.call(that);}, 250);
		return;
	}
	
	this.dom.body.style.display = block;
};

In Example 4, the show Function tests to see if the dom and dom.body variables are set. When they are not, the function re-calls itself in a quarter of a second, using the native setTimeout method. Scope is maintained by using the call Function of the show Function and passing in the scope of the original show Function. It will keep defering indefinitely, until the DOM objects are set, then it will execute the normal operation of the show Function.

This a great technique to use in conjunction with Lazy Function Definition Pattern, so that once the deferment is complete, you wont need to execute that check again. This can be a performance boost if your if statement operation is more complex than a simple existance test. You may also find it useful to send parameters into the function you are defering. Here is an example using the Lazy Function Definition Pattern and extra parameters:

Example 5: Show Improved

dialog.show = function(display) {
	var that = this;

	// deferment block; if the node doesnt exist yet, wait for it
	if (! (this.dom && this.dom.body)) {
		// notice the parameter display is passed here
		setTimeout(function() {that.show.call(that, display);}, 250);
		return;
	}
	
	// Lazy Definition Pattern
	this.show = function(display) {
		this.dom.body.style.display = display;
	};
	
	this.show(display);
};